﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Конструктор списка полей данных печати для функции СхемаКомпоновкиДанныхПечати.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * Идентификатор - Строка - имя поля.
//   * Представление - Строка - заголовок поля.
//   * ТипЗначения   - ОписаниеТипов - тип значения поля.
//   * ИмяКартинки   - Строка - картинка поля, выводится в списке доступных полей редактора макета.
//   * Порядок       - Число - используется для упорядочивания поля в списке доступных полей редактора макета.
//
Функция ТаблицаПолейДанныхПечати() Экспорт
	
	Возврат КонструкторФормул.ТаблицаПолей();
	
КонецФункции

// Конструктор списка полей данных печати для функции СхемаКомпоновкиДанныхПечати.
//
// Возвращаемое значение:
//  ДеревоЗначений:
//   * Идентификатор - Строка - имя поля.
//   * Представление - Строка - заголовок поля.
//   * ТипЗначения   - ОписаниеТипов - тип значения поля.
//   * ИмяКартинки   - Строка - картинка поля, выводится в списке доступных полей редактора макета.
//   * Порядок       - Число - используется для упорядочивания поля в списке доступных полей редактора макета.
//   * Папка         - Булево - указывает на то, что поле является папкой. В отличие от групп, папка входит в полный
//                              путь к полю.
//   * Таблица       - Булево - используется для описания табличной части. Подчиненные поля - поля этой табличной части.
//
Функция ДеревоПолейДанныхПечати() Экспорт
	
	Возврат КонструкторФормул.ДеревоПолей();
	
КонецФункции

// Формирует схему компоновки данных печати с заданным списком полей.
//
// Параметры:
//  СписокПолей - см. ТаблицаПолейДанныхПечати
//              - ДеревоЗначений  - см. ДеревоПолейДанныхПечати
// 
// Возвращаемое значение:
//  СхемаКомпоновкиДанных
// 
Функция СхемаКомпоновкиДанныхПечати(СписокПолей) Экспорт
	
	Если ТипЗнч(СписокПолей) = Тип("ТаблицаЗначений") Тогда
		Возврат СхемаКомпоновкиДанныхИзТаблицыЗначений(СписокПолей);
	ИначеЕсли ТипЗнч(СписокПолей) = Тип("ДеревоЗначений") Тогда
		Возврат СхемаКомпоновкиДанныхИзДереваЗначений(СписокПолей);
	КонецЕсли;

	ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
		"ru = 'Передан неверный тип ""%1"" в параметре ""%2""'"),
		ТипЗнч(СписокПолей), "СписокПолей");
	
КонецФункции

// Возвращает описание найденной в коллекции печатной формы.
// Если описание не существует, возвращает Неопределено.
// Функция предназначена для использования только внутри процедуры Печать.
//
// Параметры:
//  КоллекцияПечатныхФорм - см. УправлениеПечатьюПереопределяемый.ПриПечати.КоллекцияПечатныхФорм
//  Идентификатор         - Строка - идентификатор печатной формы в менеджере печати.
//
// Возвращаемое значение:
//  СтрокаТаблицыЗначений из см. УправлениеПечатьюПереопределяемый.ПриПечати.КоллекцияПечатныхФорм
//
// Пример:
//  ПечатнаяФорма = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "Квитанция");
//  Если ПечатнаяФорма <> Неопределено Тогда
//    ПечатнаяФорма.ТабличныйДокумент = ПечатьКвитанции(МассивОбъектов);
//    ПечатнаяФорма.СинонимМакета = НСтр("ru = 'Квитанция (с QR кодом)'");
//    ПечатнаяФорма.ПолныйПутьКМакету = "Документ._ДемоСчетНаОплатуПокупателю.ПФ_MXL_Квитанция";
//  КонецЕсли;
//
Функция СведенияОПечатнойФорме(КоллекцияПечатныхФорм, Идентификатор) Экспорт
	Возврат КоллекцияПечатныхФорм.Найти(ВРег(Идентификатор), "ИмяВРЕГ");
КонецФункции

// Проверить, нужно ли печатать макет.
// Функция предназначена для использования только внутри процедуры Печать.
//
// Параметры:
//  КоллекцияПечатныхФорм - ТаблицаЗначений - служебный параметр, переданный в процедуру Печать;
//  ИмяМакета             - Строка          - имя проверяемого макета.
//
// Возвращаемое значение:
//  Булево - Истина, если макет надо печатать.
//
Функция НужноПечататьМакет(КоллекцияПечатныхФорм, ИмяМакета) Экспорт
	
	Возврат КоллекцияПечатныхФорм.Найти(ВРег(ИмяМакета), "ИмяВРЕГ") <> Неопределено;
	
КонецФункции

// Добавляет табличный документ в коллекцию печатных форм.
// Процедура предназначена для использования только внутри процедуры Печать.
//
// Параметры:
//  КоллекцияПечатныхФорм - ТаблицаЗначений - служебный параметр, переданный в процедуру Печать;
//  ИмяМакета             - Строка - имя макета;
//  СинонимМакета         - Строка - представление макета;
//  ТабличныйДокумент     - ТабличныйДокумент - печатная форма документа;
//  Картинка              - Картинка - пиктограмма печатной формы;
//  ПолныйПутьКМакету     - Строка - путь к макету в дереве метаданных, например
//                                   "Документ.СчетНаОплатуПокупателю.ПФ_MXL_СчетЗаказ".
//                                   Если не указывать этот параметр, то редактирование макета пользователем будет
//                                   недоступно в форме ПечатьДокументов.
//  ИмяФайлаПечатнойФормы - Строка - имя, используемое при сохранении печатной формы в файл;
//                        - Соответствие из КлючИЗначение:
//                           * Ключ     - ЛюбаяСсылка - ссылка на объект печати;
//                           * Значение - Строка - имя файла.
//
Процедура ВывестиТабличныйДокументВКоллекцию(КоллекцияПечатныхФорм, ИмяМакета, СинонимМакета, ТабличныйДокумент,
	Картинка = Неопределено, ПолныйПутьКМакету = "", ИмяФайлаПечатнойФормы = Неопределено) Экспорт
	
	ОписаниеПечатнойФормы = КоллекцияПечатныхФорм.Найти(ВРег(ИмяМакета), "ИмяВРЕГ");
	Если ОписаниеПечатнойФормы <> Неопределено Тогда
		ОписаниеПечатнойФормы.ТабличныйДокумент = ТабличныйДокумент;
		ОписаниеПечатнойФормы.СинонимМакета = СинонимМакета;
		ОписаниеПечатнойФормы.Картинка = Картинка;
		ОписаниеПечатнойФормы.ПолныйПутьКМакету = ПолныйПутьКМакету;
		ОписаниеПечатнойФормы.ИмяФайлаПечатнойФормы = ИмяФайлаПечатнойФормы;
	КонецЕсли;
	
КонецПроцедуры

// Задает область печати объекта в табличном документе. Необходимо использовать при выводе нескольких печатных форм
// в одном табличном документе для возможности печати комплектов документов, а также для возможности сохранения
// печатных форм в отдельных файлах.
// Необходимо вызывать после формирования каждой печатной формы в табличном документе.
//
// Параметры:
//  ТабличныйДокумент - ТабличныйДокумент - печатная форма;
//  НомерСтрокиНачало - Число - позиция начала очередной области в документе;
//  ОбъектыПечати - см. УправлениеПечатьюПереопределяемый.ПриПечати.ОбъектыПечати
//  Ссылка - ЛюбаяСсылка - объект печати.
//
// Пример:
//  Пока ВыборкаПоДокументам.Следующий() Цикл
//    НомерСтрокиНачало = ТабличныйДокумент.ВысотаТаблицы + 1;
//    // ... вывод печатной формы в табличный документ ...
//    УправлениеПечатью.ЗадатьОбластьПечатиДокумента(ТабличныйДокумент, НомерСтрокиНачало, ОбъектыПечати, ВыборкаПоДокументам.Ссылка);
//  КонецЦикла;
//
Процедура ЗадатьОбластьПечатиДокумента(ТабличныйДокумент, НомерСтрокиНачало, ОбъектыПечати, Ссылка) Экспорт
	
	Если Не ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Ссылка)) Тогда
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Недопустимое значение параметра ""Ссылка"",
			|ожидалось значение ссылочного типа, передано значение: ""%1"" (тип %2)'"), Ссылка, ТипЗнч(Ссылка));
		Попытка // Такая конструкция нужна для проброса стека в журнал регистрации.
			ВызватьИсключение ТекстСообщения;
		Исключение
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Печать'", ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , ,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		Возврат;
	КонецЕсли;
	
	Элемент = ОбъектыПечати.НайтиПоЗначению(Ссылка);
	Если Элемент = Неопределено Тогда
		ИмяОбласти = "Документ_" + Формат(ОбъектыПечати.Количество() + 1, "ЧН=; ЧГ=");
		ОбъектыПечати.Добавить(Ссылка, ИмяОбласти);
	Иначе
		ИмяОбласти = Элемент.Представление;
	КонецЕсли;
	
	НомерСтрокиОкончание = ТабличныйДокумент.ВысотаТаблицы;
	ТабличныйДокумент.Область(НомерСтрокиНачало, , НомерСтрокиОкончание, ).Имя = ИмяОбласти;
	
	Если Не НастройкиПечати().ИспользоватьПодписиИПечати Тогда
		Возврат;
	КонецЕсли;
	
	Для Каждого Рисунок Из ТабличныйДокумент.Рисунки Цикл
		ЭтоПодписьИПечать = Ложь;
		Для Каждого ИмяОбластиСПодписьюИПечатью Из ПрефиксыИменОбластейСПодписьюИПечатью() Цикл
			Если СтрНайти(Рисунок.Имя, ИмяОбластиСПодписьюИПечатью) > 0 Тогда
				ЭтоПодписьИПечать = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		Если Не ЭтоПодписьИПечать Тогда
			Продолжить;
		КонецЕсли;
		Если Рисунок.ТипРисунка = ТипРисункаТабличногоДокумента.Картинка И СтрНайти(Рисунок.Имя, "_Документ_") = 0 Тогда
			Рисунок.Имя = Рисунок.Имя + "_" + ИмяОбласти;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Возвращает список внешних печатных форм.
//
// Параметры:
//  ПолноеИмяОбъектаМетаданных - Строка - полное имя объекта метаданных, для которого необходимо получить список
//                                        печатных форм.
//
// Возвращаемое значение:
//  СписокЗначений:
//   * Значение      - Строка - идентификатор печатной формы;
//   * Представление - Строка - представление печатной формы.
//
Функция СписокПечатныхФормИзВнешнихИсточников(ПолноеИмяОбъектаМетаданных) Экспорт
	
	ВнешниеПечатныеФормы = Новый СписокЗначений;
	Если Не ПустаяСтрока(ПолноеИмяОбъектаМетаданных) И ПолноеИмяОбъектаМетаданных <> "Справочник.ИдентификаторыОбъектовМетаданных" Тогда
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
			МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
			МодульДополнительныеОтчетыИОбработки.ПриПолученииСпискаВнешнихПечатныхФорм(ВнешниеПечатныеФормы, ПолноеИмяОбъектаМетаданных);
		КонецЕсли;
	КонецЕсли;
	
	Возврат ВнешниеПечатныеФормы;
	
КонецФункции

// Возвращает список команд печати для указанной формы.
//
// Параметры:
//  Форма - ФормаКлиентскогоПриложения
//        - Строка - форма или полное имя формы, для которой необходимо получить список
//                   команд печати.
//  СписокОбъектов - Массив - коллекция объектов метаданных, команды печати которых необходимо использовать при составлении
//                            списка команд печати для указанной формы.
// Возвращаемое значение:
//   см. СоздатьКоллекциюКомандПечати
//
Функция КомандыПечатиФормы(Форма, СписокОбъектов = Неопределено) Экспорт
	
	Если ТипЗнч(Форма) = Тип("ФормаКлиентскогоПриложения") Тогда
		ИмяФормы = Форма.ИмяФормы;
	Иначе
		ИмяФормы = Форма;
	КонецЕсли;
	
	ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ИмяФормы);
	Если ОбъектМетаданных <> Неопределено И Не Метаданные.ОбщиеФормы.Содержит(ОбъектМетаданных) Тогда
		ОбъектМетаданных = ОбъектМетаданных.Родитель();
	Иначе
		ОбъектМетаданных = Неопределено;
	КонецЕсли;

	Если ОбъектМетаданных <> Неопределено Тогда
		СсылкаОМ = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных);
	КонецЕсли;
	
	КомандыПечати = СоздатьКоллекциюКомандПечати();
	
	СтандартнаяОбработка = Истина;
	ИнтеграцияПодсистемБСП.ПередДобавлениемКомандПечати(ИмяФормы, КомандыПечати, СтандартнаяОбработка);
	УправлениеПечатьюПереопределяемый.ПередДобавлениемКомандПечати(ИмяФормы, КомандыПечати, СтандартнаяОбработка);
	
	Если СтандартнаяОбработка Тогда
		Если СписокОбъектов <> Неопределено Тогда
			ЗаполнитьКомандыПечатиДляСпискаОбъектов(СписокОбъектов, КомандыПечати);
		ИначеЕсли ОбъектМетаданных = Неопределено Тогда
			Возврат КомандыПечати;
		Иначе
			ЭтоЖурналДокументов = ОбщегоНазначения.ЭтоЖурналДокументов(ОбъектМетаданных);
			НастройкиСписка = Новый Структура;
			НастройкиСписка.Вставить("МенеджерКомандПечати", ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя()));
			НастройкиСписка.Вставить("АвтоматическоеЗаполнение", ЭтоЖурналДокументов);
			Если ЭтоЖурналДокументов Тогда
				ИнтеграцияПодсистемБСП.ПриПолученииНастроекСпискаКомандПечати(НастройкиСписка);
				УправлениеПечатьюПереопределяемый.ПриПолученииНастроекСпискаКомандПечати(НастройкиСписка);
			КонецЕсли;
			
			Если НастройкиСписка.АвтоматическоеЗаполнение Тогда
				Если ЭтоЖурналДокументов Тогда
					ЗаполнитьКомандыПечатиДляСпискаОбъектов(ОбъектМетаданных.РегистрируемыеДокументы, КомандыПечати);
				КонецЕсли;
			Иначе
				КомандыПечати = КомандыПечатиОбъекта(ОбъектМетаданных);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Для Каждого КомандаПечати Из КомандыПечати Цикл
		Если КомандаПечати.Порядок = 0 Тогда
			КомандаПечати.Порядок = 50;
		КонецЕсли;
		КомандаПечати.ДополнительныеПараметры.Вставить("ДополнитьКомплектВнешнимиПечатнымиФормами", КомандаПечати.ДополнитьКомплектВнешнимиПечатнымиФормами);
	КонецЦикла;
	
	Если ОбъектМетаданных <> Неопределено Тогда
		УстановитьНастройкиКомандПечати(КомандыПечати, СсылкаОМ);
	КонецЕсли;
	
	КомандыПечати.Сортировать("Порядок Возр, Представление Возр");
	
	ЧастиИмени = СтрРазделить(ИмяФормы, ".");
	КраткоеИмяФормы = ЧастиИмени[ЧастиИмени.Количество()-1];
	
	// фильтр по именам форм
	Для НомерСтроки = -КомандыПечати.Количество() + 1 По 0 Цикл
		КомандаПечати = КомандыПечати[-НомерСтроки];
		СписокФорм = СтрРазделить(КомандаПечати.СписокФорм, ",", Ложь);
		Если СписокФорм.Количество() > 0 И СписокФорм.Найти(КраткоеИмяФормы) = Неопределено Тогда
			КомандыПечати.Удалить(КомандаПечати);
		КонецЕсли;
	КонецЦикла;
	
	ОпределитьВидимостьКомандПечатиПоФункциональнымОпциям(КомандыПечати, Форма);
	
	Возврат КомандыПечати;
	
КонецФункции

// Создает пустую таблицу с описанием команд печати.
// Таблица команд печати передается в процедуры ДобавитьКомандыПечати, 
// размещенные в модулях менеджеров объектов конфигурации, которые перечислены в процедуре
// УправлениеПечатьюПереопределяемый.ПриОпределенииОбъектовСКомандамиПечати.
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//
//   * Идентификатор - Строка - идентификатор команды печати, по которому менеджер печати определяет печатную
//                             форму, которую необходимо сформировать.
//                             Например, "СчетЗаказ".
//
//                              Для печати нескольких печатных форм можно указывать одновременно несколько их
//                              идентификаторов (строкой, через запятую либо массивом строк), например:
//                              "СчетЗаказ,ГарантийноеПисьмо".
//
//                              Если необходимо задать количество копий печати для печатной формы, то ее
//                              идентификатор нужно продублировать столько раз, сколько копий необходимо
//                              сформировать. При этом следует учитывать, что порядок следования печатных
//                              форм в комплекте будет соответствовать порядку идентификаторов печатных форм,
//                              указанных в этом параметре. Например (2 счета на оплату + 1 гарантийное письмо):
//                              "СчетЗаказ,СчетЗаказ,ГарантийноеПисьмо".
//
//                              Идентификатор печатной формы может содержать в себе и альтернативный менеджер
//                              печати, если он отличается от указанного в параметре МенеджерПечати,
//                              например: "СчетЗаказ,Обработка.ПечатнаяФорма.ГарантийноеПисьмо".
//
//                              В этом примере ГарантийноеПисьмо формируется в менеджере печати
//                              Обработка.ПечатнаяФорма, а СчетЗаказ - в менеджере печати, указанном в
//                              параметре МенеджерПечати.
//                              
//                              Для печатных форм, менеджером печати которых является общий модуль
//                             "УправлениеПечатью", в качестве идентификатора необходимо указать полный путь к макету.
//                             Например, "Документ._ДемоСчетНаОплатуПокупателю.ПФ_MXL_СчетНаОплату".
//
//                   - Массив - список идентификаторов команд печати.
//
//   * Представление - Строка            - представление команды в меню Печать. 
//                                         Например, "Счет на оплату".
//
//   * МенеджерПечати - Строка           - (необязательный) имя объекта, в модуле менеджера которого располагается
//                                        процедура Печать, формирующая табличные документы для этой команды.
//                                        Если печатная форма формируется автоматически по данным печати и макету, то
//                                        в параметре необходимо указать общий модуль "УправлениеПечатью".
//                                        Значение по умолчанию - имя модуля менеджера объекта.
//                                        Например, "Документ.СчетНаОплатуПокупателю".
//   * ТипыОбъектовПечати - Массив       - (необязательный) список типов объектов, для которых предназначена команда
//                                        печати. Параметр предназначен для команд печати в журналах документов, где
//                                        требуется проверка передаваемого типа объекта перед вызовом менеджера печати.
//                                        Если список не заполнен, то при автоматическом создании списка команд печати
//                                        в журнале документов он заполняется типом объекта, из которого была
//                                        импортирована команда печати.
//
//   * Обработчик    - Строка            - (необязательный) клиентский обработчик команды, в который необходимо передать
//                                        управление вместо стандартного обработчика команды Печать. Используется,
//                                        например, когда печатная форма формируется на клиенте.
//                                        Формат "<ИмяОбщегоМодуля>.<ИмяПроцедуры>" используется, когда процедура размещена
//                                        в общем модуле.
//                                        Формат "<ИмяПроцедуры>" используется, когда процедура размещена
//                                        в модуле основной формы отчета или обработки, указанной в МенеджерПечати.
//                                        Например,
//                                          КомандаПечати.Обработчик = "_ДемоСтандартныеПодсистемыКлиент.ПечатьСчетовНаОплатуПокупателю";
//                                        Пример обработчика в модуле формы:
//                                          // Формирует печатную форму <представление печатной формы>.
//                                          //
//                                          // Параметры:
//                                          //   ПараметрыПечати - Структура - сведения о печатной форме.
//                                          //       * ОбъектыПечати - Массив - массив ссылок выбранных объектов.
//                                          //       * Форма - ФормаКлиентскогоПриложения - форма, из которой вызвана
//                                          //                                              команда печати.
//                                          //       * ДополнительныеПараметры - Структура - дополнительные параметры печати.
//                                          //       Прочие ключи структуры соответствуют колонкам таблицы КомандыПечати,
//                                          //       подробнее см. в функции УправлениеПечатью.СоздатьКоллекциюКомандПечати.
//                                          //
//                                          &НаКлиенте
//                                          Функция <ИмяФункции>(ПараметрыПечати) Экспорт
//                                          	// Обработчик печати.
//                                          КонецФункции
//                                        Следует иметь в виду, что обработчик вызывается при помощи метода Вычислить,
//                                        поэтому в качестве обработчика может выступать только функция.
//                                        При этом возвращаемое значение функции никак в дальнейшем не используется подсистемой.
//
//   * Порядок       - Число             - (необязательный) Значение от 1 до 100, указывающее порядок размещения команды
//                                        по отношению к другим командам. Сортировка команд меню Печать осуществляется
//                                        сначала по полю Порядок, затем по представлению.
//                                        Значение по умолчанию - 50.
//
//   * Картинка      - Картинка          - (необязательный) Картинка, которая отображается возле команды в меню Печать.
//                                         Например, БиблиотекаКартинок.ФорматPDF.
//
//   * СписокФорм    - Строка            - (необязательный) Имена форм через запятую, в которых должна отображаться
//                                        команда. Если параметр не указан, то команда печати будет отображаться во
//                                        всех формах объекта, где встроена подсистема Печать.
//                                         Например, "ФормаДокумента".
//
//   * МестоРазмещения - Строка          - (необязательный) Имя группы формы, в которую необходимо разместить
//                                        команду печати. Параметр необходимо использовать только в случае, когда на
//                                        форме размещается более одного подменю "Печать". В остальных случаях место
//                                        размещения необходимо задавать в модуле формы при вызове
//                                        метода ПодключаемыеКоманды.ПриСозданииНаСервере.
//                                        
//   * ЗаголовокФормы  - Строка          - (необязательный) Произвольная строка, переопределяющая стандартных заголовок
//                                        формы "Печать документов". Например, "Настраиваемый комплект".
//
//   * ФункциональныеОпции - Строка      - (необязательный) Имена функциональных опций через запятую, от которых зависит
//                                        доступность команды печати.
//
//   * УсловияВидимости - Массив         - (необязательный) Коллекция условий видимости команды в зависимости от
//                                        контекста. Условия видимости команды задаются при помощи процедуры 
//                                        ДобавитьУсловиеВидимостиКоманды.
//                                        Если параметр не задан, команда видна вне зависимости от контекста.
//                                        
//   * ПроверкаПроведенияПередПечатью    - Булево - (необязательный) Признак необходимости проверки проведенности
//                                        документов перед печатью. Если выбран хотя бы один непроведенный документ, то
//                                        перед выполнением команды печати возникает диалог проведения.
//                                        Для непроведенных документов команда печати не выполняется.
//                                        Если параметр не указан, то проверка проведенности не выполняется.
//
//   * СразуНаПринтер - Булево           - (необязательный) Признак необходимости печати документов без предварительного
//                                        просмотра, сразу на принтер. Если параметр не указан, то при выборе команды
//                                        печати открывается форма предварительного просмотра "Печать документов".
//
//   * ФорматСохранения - ТипФайлаТабличногоДокумента - (необязательный) Применяется для быстрого сохранения печатной
//                                        формы (без дополнительных действий) в различные форматы, отличные от mxl.
//                                        Если параметр не указан, то формируется обычный mxl.
//                                        Например, ТипФайлаТабличногоДокумента.PDF.
//
//                                        При выборе команды печати сразу открывается сформированный в формате pdf
//                                        документ.
//
//   * ПереопределитьПользовательскиеНастройкиКоличества - Булево - (необязательный) Признак необходимости отключения в
//                                        форме ПечатьДокументов механизма сохранения/восстановления выбранного
//                                        пользователем количества экземпляров на печать. Если параметр не указан, то
//                                        механизм сохранения/восстановления настроек будет работать при открытии формы.
//                                        ПечатьДокументов.
//
//   * ДополнитьКомплектВнешнимиПечатнымиФормами - Булево - (необязательный) Признак необходимости дополнить комплект
//                                        документов всеми подключенными к объекту внешними печатными формами
//                                        (подсистема ДополнительныеОтчетыИОбработки). Если параметр не указан, внешние
//                                        печатные формы не добавляются в комплект.
//
//   * ФиксированныйКомплект - Булево    - (необязательный) Признак необходимости блокировки от изменения пользователем
//                                        состава комплекта документов. Если параметр не указан, то пользователь сможет
//                                        исключать отдельные печатные формы из комплекта в форме ПечатьДокументов, а
//                                        также изменять их количество.
//
//   * ДополнительныеПараметры - Структура - (необязательный) произвольные параметры для передачи в менеджер печати.
//
//   * НеВыполнятьЗаписьВФорме - Булево  - (необязательный) Признак необходимости отключения механизма записи объекта
//                                        перед выполнением команды печати. Используется в исключительных случаях. Если
//                                        параметр не указан, производится запись объекта в случае, если в форме
//                                        объекта установлен признак модифицированности.
//
//   * ТребуетсяРасширениеРаботыСФайлами - Булево - (необязательный) Признак необходимости подключения расширения для работы 
//                                        с 1С:Предприятием перед выполнением команды. Если параметр не указан, расширение
//                                        подключаться не будет.
//
Функция СоздатьКоллекциюКомандПечати() Экспорт
	
	Результат = Новый ТаблицаЗначений;
	
	// описание
	Результат.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
	
	//////////
	// Опции (необязательные параметры).
	
	// менеджер печати
	Результат.Колонки.Добавить("МенеджерПечати", Неопределено);
	Результат.Колонки.Добавить("ТипыОбъектовПечати", Новый ОписаниеТипов("Массив"));
	
	// Альтернативный обработчик команды.
	Результат.Колонки.Добавить("Обработчик", Новый ОписаниеТипов("Строка"));
	
	// представление
	Результат.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число"));
	Результат.Колонки.Добавить("Картинка", Новый ОписаниеТипов("Картинка"));
	// Имена форм для размещения команд, разделитель - запятая.
	Результат.Колонки.Добавить("СписокФорм", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("МестоРазмещения", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("ЗаголовокФормы", Новый ОписаниеТипов("Строка"));
	// Имена функциональных опций, влияющих на видимость команды, разделитель - запятая.
	Результат.Колонки.Добавить("ФункциональныеОпции", Новый ОписаниеТипов("Строка"));
	
	// Динамические условия видимости.
	Результат.Колонки.Добавить("УсловияВидимости", Новый ОписаниеТипов("Массив"));
	
	// проверка проведения
	Результат.Колонки.Добавить("ПроверкаПроведенияПередПечатью");
	
	// вывод
	Результат.Колонки.Добавить("СразуНаПринтер", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ФорматСохранения"); // ТипФайлаТабличногоДокумента
	
	// настройки комплектов
	Результат.Колонки.Добавить("ПереопределитьПользовательскиеНастройкиКоличества", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ДополнитьКомплектВнешнимиПечатнымиФормами", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ФиксированныйКомплект", Новый ОписаниеТипов("Булево")); // запрет изменения комплекта
	
	// дополнительные параметры
	Результат.Колонки.Добавить("ДополнительныеПараметры", Новый ОписаниеТипов("Структура"));
	
	// Специальный режим выполнения команды
	// по умолчанию выполняется запись модифицированного объекта перед выполнением команды.
	Результат.Колонки.Добавить("НеВыполнятьЗаписьВФорме", Новый ОписаниеТипов("Булево"));
	
	// Для использования макетов офисных документов в веб-клиенте.
	Результат.Колонки.Добавить("ТребуетсяРасширениеРаботыСФайлами", Новый ОписаниеТипов("Булево"));
	
	// Для служебного использования.
	Результат.Колонки.Добавить("СкрытаФункциональнымиОпциями", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("УникальныйИдентификатор", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("Отключена", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ИмяКомандыНаФорме", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("УсловияВидимостиПоТипамОбъектов", Новый ОписаниеТипов("Соответствие"));
	Результат.Колонки.Добавить("ВыполнятьВФоновомЗадании");
	
	Возврат Результат;
	
КонецФункции

// Задает условия видимости команды печати на форме в зависимости от контекста.
//
// Параметры:
//  КомандаПечати  - СтрокаТаблицыЗначений - элемент коллекции КомандыПечати в процедуре ДобавитьКомандыПечати:
//   * УсловияВидимости - Массив - список условий видимости;
//  Реквизит       - Строка                - имя реквизита объекта;
//  Значение       - Произвольный          - значение реквизита объекта;
//  МетодСравнения - ВидСравнения          - вид сравнения значений. Допустимые для использования виды: 
//                                           Равно, НеРавно, Больше, БольшеИлиРавно, Меньше, МеньшеИлиРавно, ВСписке, НеВСписке.
//                                           Значение по умолчанию - Равно.
//
Процедура ДобавитьУсловиеВидимостиКоманды(КомандаПечати, Реквизит, Значение, Знач МетодСравнения = Неопределено) Экспорт
	Если МетодСравнения = Неопределено Тогда
		МетодСравнения = ВидСравнения.Равно;
	КонецЕсли;
	УсловиеВидимости = Новый Структура;
	УсловиеВидимости.Вставить("Реквизит", Реквизит);
	УсловиеВидимости.Вставить("ВидСравнения", МетодСравнения);
	УсловиеВидимости.Вставить("Значение", Значение);
	КомандаПечати.УсловияВидимости.Добавить(УсловиеВидимости);
КонецПроцедуры

// Используется при переносе макета (объекта метаданных) печатной формы в другой объект.
// Предназначена для вызова в процедуре заполнения данных обновления (для "отложенного" обработчика).
// Регистрирует новый адрес макета для обработки.
//
// Параметры:
//  ИмяМакета   - Строка - новое имя макета в формате
//                         "Документ.<ИмяДокумента>.<ИмяМакета>"
//                         "Обработка.<ИмяОбработки>.<ИмяМакета>"
//                         "ОбщийМакет.<ИмяМакета>".
//  Параметры - см. ОбновлениеИнформационнойБазы.ОсновныеПараметрыОтметкиКОбработке.
//
Процедура ЗарегистрироватьНовоеИмяМакета(ИмяМакета, Параметры) Экспорт
	ЧастиИмениМакета = ЧастиИмениМакета(ИмяМакета);
	
	НаборЗаписей = РегистрыСведений.ПользовательскиеМакетыПечати.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.ИмяМакета.Установить(ЧастиИмениМакета.ИмяМакета);
	НаборЗаписей.Отбор.Объект.Установить(ЧастиИмениМакета.ИмяОбъекта);
	
	ОбновлениеИнформационнойБазы.ОтметитьКОбработке(Параметры, НаборЗаписей);
КонецПроцедуры

// Используется при переносе макета (объекта метаданных) печатной формы в другой объект.
// Предназначена для вызова в "отложенном" обработчике обновления.
// Переносит пользовательские данные, относящиеся к макету, на новый адрес.
//
// Параметры:
//  Макеты     - Соответствие из КлючИЗначение - сведения о прежних и новых именах макетов в формате
//                              "Документ.<ИмяДокумента>.<ИмяМакета>"
//                              "Обработка.<ИмяОбработки>.<ИмяМакета>"
//                              "ОбщийМакет.<ИмяМакета>":
//   * Ключ     - Строка - новое имя макета.
//   * Значение - Строка - прежнее имя макета.
//
//  Параметры - Структура - параметры, передаваемые в "отложенный" обработчик обновления.
//
Процедура ПеренестиПользовательскиеМакеты(Макеты, Параметры) Экспорт
	
	ДанныеДляОбработки = ОбновлениеИнформационнойБазы.ВыбратьИзмеренияНезависимогоРегистраСведенийДляОбработки(Параметры.Очередь, "РегистрСведений.ПользовательскиеМакетыПечати");
	Пока ДанныеДляОбработки.Следующий() Цикл
		НовоеИмяМакета = ДанныеДляОбработки.Объект + "." + ДанныеДляОбработки.ИмяМакета;
		ПрежнееИмяМакета = Макеты[НовоеИмяМакета];
		ЧастиИмениМакета = ЧастиИмениМакета(ПрежнееИмяМакета);
		
		МенеджерЗаписи = РегистрыСведений.ПользовательскиеМакетыПечати.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.ИмяМакета = ЧастиИмениМакета.ИмяМакета;
		МенеджерЗаписи.Объект = ЧастиИмениМакета.ИмяОбъекта;
		МенеджерЗаписи.Прочитать();
		
		НаборЗаписей = РегистрыСведений.ПользовательскиеМакетыПечати.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.ИмяМакета.Установить(ДанныеДляОбработки.ИмяМакета);
		НаборЗаписей.Отбор.Объект.Установить(ДанныеДляОбработки.Объект);
		
		Если МенеджерЗаписи.Выбран() Тогда
			Запись = НаборЗаписей.Добавить();
			Запись.ИмяМакета = ДанныеДляОбработки.ИмяМакета;
			Запись.Объект = ДанныеДляОбработки.Объект;
			ЗаполнитьЗначенияСвойств(Запись, МенеджерЗаписи, , "ИмяМакета,Объект");
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(НаборЗаписей);
			МенеджерЗаписи.Удалить();
		Иначе
			ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки(НаборЗаписей);
		КонецЕсли;
	КонецЦикла;
	Параметры.ОбработкаЗавершена = ОбновлениеИнформационнойБазы.ОбработкаДанныхЗавершена(Параметры.Очередь, "РегистрСведений.ПользовательскиеМакетыПечати");
	
КонецПроцедуры

// Предоставляет дополнительный профиль доступа "Редактирование, отправка по почте, сохранение в файл печатных форм (дополнительно)".
// Предназначена для использования в процедуре ПриЗаполненииПоставляемыхПрофилейГруппДоступа модуля УправлениеДоступомПереопределяемый.
//
// Параметры:
//  ОписанияПрофилей - см. УправлениеДоступомПереопределяемый.ПриЗаполненииПоставляемыхПрофилейГруппДоступа.ОписанияПрофилей
//
Процедура ЗаполнитьПрофильРедактированиеПечатныхФорм(ОписанияПрофилей) Экспорт
	
	МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
	ОписаниеПрофиля = МодульУправлениеДоступом.НовоеОписаниеПрофиляГруппДоступа();
	ОписаниеПрофиля.Родитель      = "ДополнительныеПрофили";
	ОписаниеПрофиля.Идентификатор = "70179f20-2315-11e6-9bff-d850e648b60c";
	ОписаниеПрофиля.Наименование = НСтр("ru = 'Редактирование, отправка по почте, сохранение в файл печатных форм (дополнительно)'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	ОписаниеПрофиля.Описание = НСтр("ru = 'Дополнительно назначается пользователям, которым должна быть доступна возможность редактирования,
		|перед печатью, отправка по почте и сохранение в файл сформированных печатных форм.'");
	ОписаниеПрофиля.Роли.Добавить("РедактированиеПечатныхФорм");
	ОписанияПрофилей.Добавить(ОписаниеПрофиля);
	
КонецПроцедуры

// Добавляет к параметру НаборОбластей новую запись об области.
//
// Параметры:
//   ОбластиМакетаОфисногоДокумента - Массив - набор областей (массив структур) макета офисного документа.
//   ИмяОбласти                     - Строка - имя добавляемой области.
//   ТипОбласти                     - Строка - тип области:
//    ВерхнийКолонтитул;
//    НижнийКолонтитул;
//    Общая;
//    СтрокаТаблицы;
//    Список.
//
// Пример:
//	Функция ОбластиМакетаОфисногоДокумента()
//	
//		Области = Новый Структура;
//	
//		УправлениеПечатью.ДобавитьОписаниеОбласти(Области, "ВерхнийКолонтитул",	"ВерхнийКолонтитул");
//		УправлениеПечатью.ДобавитьОписаниеОбласти(Области, "НижнийКолонтитул",	"НижнийКолонтитул");
//		УправлениеПечатью.ДобавитьОписаниеОбласти(Области, "Заголовок",			"Общая");
//	
//		Возврат Области;
//	
//	КонецФункции
//
Процедура ДобавитьОписаниеОбласти(ОбластиМакетаОфисногоДокумента, Знач ИмяОбласти, Знач ТипОбласти) Экспорт
	
	НоваяОбласть = Новый Структура;
	
	НоваяОбласть.Вставить("ИмяОбласти", ИмяОбласти);
	НоваяОбласть.Вставить("ТипОбласти", ТипОбласти);
	
	ОбластиМакетаОфисногоДокумента.Вставить(ИмяОбласти, НоваяОбласть);
	
КонецПроцедуры

// Получает за один вызов всю необходимую информацию для печати: данные объектов по макетам, двоичные
// данные макетов, описание областей макетов.
// Для вызова из клиентских модулей печати форм по макетам офисных документов.
//
// Параметры:
//   ИмяМенеджераПечати - Строка - имя для обращения к менеджеру объекта, например "Документ.<Имя документа>".
//   ИменаМакетов       - Строка - имена макетов, по которым будут формироваться печатные формы.
//   СоставДокументов   - Массив - ссылки на объекты информационной базы (должны быть одного типа).
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение - коллекция ссылок на объекты и их данные:
//   * Ключ - ЛюбаяСсылка - ссылка на объект информационной базы;
//   * Значение - Структура:
//       ** Ключ - Строка - имя макета;
//       ** Значение - Структура - данные объекта.
//
Функция МакетыИДанныеОбъектовДляПечати(Знач ИмяМенеджераПечати, Знач ИменаМакетов, Знач СоставДокументов) Экспорт
	
	МассивИменМакетов = СтрРазделить(ИменаМакетов, ", ", Ложь);
	
	МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИмяМенеджераПечати);
	МакетыИДанные = МенеджерОбъекта.ПолучитьДанныеПечати(СоставДокументов, МассивИменМакетов);
	МакетыИДанные.Вставить("ЛокальныйКаталогФайловПечати", Неопределено); // Для обратной совместимости.
	
	Если НЕ МакетыИДанные.Макеты.Свойство("ТипыМакетов") Тогда
		МакетыИДанные.Макеты.Вставить("ТипыМакетов", Новый Соответствие); // Для обратной совместимости.
	КонецЕсли;
	
	Возврат МакетыИДанные;
	
КонецФункции

// Возвращает макет печатной формы по полному пути к макету.
//
// Если конфигурация рассчитана на несколько языков, в ней могут быть предусмотрены несколько макетов для этих языков:
// - ПФ_DOC_СчетНаОплату_ru
// - ПФ_DOC_СчетНаОплату_en
// - и т.п.
// В этом случае при поиске нужного макета учитывается следующий приоритет:
// 1) на языке, указанном в параметре КодЯзыка,
// 2) на языке конфигурации (ОбщегоНазначения.КодОсновногоЯзыка()),
// 3) без указания языка.
//
// Параметры:
//  ПутьКМакету - Строка - полный путь к макету в формате:
//                         "Документ.<ИмяДокумента>.<ИмяМакета>"
//                         "Обработка.<ИмяОбработки>.<ИмяМакета>"
//                         "ОбщийМакет.<ИмяМакета>".
//  КодЯзыка    - Строка - язык, на котором требуется получить макет.
//                         Состоит из кода языка по ISO 639-1 и, опционально, кода страны по ISO 3166-1, разделенных
//                         символом подчеркивания. Примеры: "en", "en_US", "en_GB", "ru", "ru_RU".
//
// Возвращаемое значение:
//  ТабличныйДокумент, ДвоичныеДанные - макет.
//
Функция МакетПечатнойФормы(ПутьКМакету, Знач КодЯзыка = Неопределено) Экспорт
	
	Если ЗначениеЗаполнено(КодЯзыка) Тогда
		КодЯзыка = СтрРазделить(КодЯзыка, "_", Истина)[0];
	КонецЕсли;
	
	ЗапомнитьПоследнийИспользованныйМакет(ПутьКМакету);
	
	Возврат НайтиМакет(ПутьКМакету, КодЯзыка);
	
КонецФункции

// Проверяет, использование пользовательского макет вместо поставляемого.
//
// Параметры:
//  ПутьКМакету - Строка - полный путь к макету в формате:
//                         "Документ.<ИмяДокумента>.<ИмяМакета>"
//                         "Обработка.<ИмяОбработки>.<ИмяМакета>"
//                         "ОбщийМакет.<ИмяМакета>".
// Возвращаемое значение:
//  Булево - Истина, если используется пользовательский макет.
//
Функция ИспользуетсяПользовательскийМакет(ПутьКМакету) Экспорт
	
	Если СтрНачинаетсяС(ПутьКМакету, "ПФ_") Тогда // Нет поставляемого макета.
		Возврат Ложь;
	КонецЕсли;
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Макет ""%1"" не существует. Операция прервана.'"), ПутьКМакету);
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	ИмяМакета = ЧастиПути[ЧастиПути.ВГраница()];
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ПользовательскиеМакетыПечати.ИмяМакета КАК ИмяМакета
	|ИЗ
	|	РегистрСведений.ПользовательскиеМакетыПечати КАК ПользовательскиеМакетыПечати
	|ГДЕ
	|	ПользовательскиеМакетыПечати.Объект = &Объект
	|	И ПользовательскиеМакетыПечати.ИмяМакета ПОДОБНО &ИмяМакета СПЕЦСИМВОЛ ""~""
	|	И ПользовательскиеМакетыПечати.Использование";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.Параметры.Вставить("Объект", ИмяОбъекта);
	Запрос.Параметры.Вставить("ИмяМакета", ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ИмяМакета) + "%");
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	СписокМакетов = Новый Соответствие;
	Если Выборка.Следующий() Тогда
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// Проверяет, был ли изменен поставляемый макет по сравнению с предыдущей версией конфигурации.
//
// Параметры:
//  ПутьКМакету - Строка - полный путь к макету в формате:
//                         "Документ.<ИмяДокумента>.<ИмяМакета>"
//                         "Обработка.<ИмяОбработки>.<ИмяМакета>"
//                         "ОбщийМакет.<ИмяМакета>".
// Возвращаемое значение:
//  Булево - Истина, если макет был изменен.
//
Функция ПоставляемыйМакетИзменен(ПутьКМакету) Экспорт
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Макет ""%1"" не существует. Операция прервана.'"), ПутьКМакету);
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	ИмяМакета = ЧастиПути[ЧастиПути.ВГраница()];
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	ОбъектМетаданных = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ИмяОбъекта);
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ПоставляемыеМакетыПечати.ПредыдущаяКонтрольнаяСумма <> """"
	|		И ПоставляемыеМакетыПечати.КонтрольнаяСумма <> ПоставляемыеМакетыПечати.ПредыдущаяКонтрольнаяСумма КАК Изменен,
	|	ПоставляемыеМакетыПечати.ИмяМакета КАК ИмяМакета
	|ИЗ
	|	РегистрСведений.ОбщиеПоставляемыеМакетыПечати КАК ПоставляемыеМакетыПечати
	|ГДЕ
	|	ПоставляемыеМакетыПечати.Объект = &Объект
	|	И ПоставляемыеМакетыПечати.ИмяМакета ПОДОБНО &ИмяМакета СПЕЦСИМВОЛ ""~""
	|	И ПоставляемыеМакетыПечати.ВерсияМакета = &ВерсияМакета
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ПоставляемыеМакетыПечати.ПредыдущаяКонтрольнаяСумма <> """"
	|		И ПоставляемыеМакетыПечати.КонтрольнаяСумма <> ПоставляемыеМакетыПечати.ПредыдущаяКонтрольнаяСумма,
	|	ПоставляемыеМакетыПечати.ИмяМакета
	|ИЗ
	|	РегистрСведений.ПоставляемыеМакетыПечати КАК ПоставляемыеМакетыПечати
	|ГДЕ
	|	ПоставляемыеМакетыПечати.Объект = &Объект
	|	И ПоставляемыеМакетыПечати.ИмяМакета ПОДОБНО &ИмяМакета СПЕЦСИМВОЛ ""~""
	|	И ПоставляемыеМакетыПечати.ВерсияМакета = &ВерсияМакета";
	
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.Параметры.Вставить("Объект", ОбъектМетаданных);
	Запрос.Параметры.Вставить("ИмяМакета", ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ИмяМакета) + "%");
	Запрос.Параметры.Вставить("ВерсияМакета", Метаданные.Версия);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	СписокМакетов = Новый Соответствие;
	Пока Выборка.Следующий() Цикл
		СписокМакетов.Вставить(Выборка.ИмяМакета, Выборка.Изменен);
	КонецЦикла;
	
	ИменаПоиска = ИменаМакета(ИмяМакета);
	
	Для Каждого ИмяПоиска Из ИменаПоиска Цикл
		Изменен = СписокМакетов[ИмяПоиска];
		Если Изменен <> Неопределено Тогда
			Возврат Изменен;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

// Переключает использование пользовательского макета на макет из конфигурации.
// Применяется в случае, когда макет печатной формы конфигурации и/или алгоритм вывода изменены без поддержки обратной
// совместимости с макетом предыдущей версии конфигурации.
// Для использования в обработчиках обновления.
//
// В общем случае при внесении изменений в макеты и процедуры формирования печатных форм необходимо учитывать 
// возможность того, что макеты могут быть изменены пользователями (т.е. взят за основу типовой макет из конфигурации
// и в него добавлен статический текст, изменен шрифт, цвет и другое оформление ячеек, которое не требует программной 
// обработки со стороны алгоритмов конфигурации).
//
// Однако в ряде случаев точное следование порядку заполнения форм важнее, чем совместимость с возможными изменениями 
// пользователя в макетах предыдущих версий (например, это справедливо для строго регламентированных печатных форм, 
// при нарушении порядка их применения контролирующие органы могут накладывать штрафы, отказывать в проведении
// операций, в налоговых вычетах и т.п. - в них недопустимы сокращение количества полей на форме, перекомпоновка).
// Примерами таких форм являются счет-фактура, созданные на его основе УПД и УКД, кассовые ордера (КО-1 и КО-2), 
// платежное поручение.
// Поэтому если у пользователя есть измененный макет, то при обновлении его следует отключать, чтобы эти печатные формы
// формировались корректно.
// 
//
// Параметры:
//  ПутьКМакету - Строка - полный путь к макету в формате:
//                         "Документ.<ИмяДокумента>.<ИмяМакета>"
//                         "Обработка.<ИмяОбработки>.<ИмяМакета>"
//                         "ОбщийМакет.<ИмяМакета>".
//
Процедура ОтключитьПользовательскийМакет(ПутьКМакету) Экспорт
	
	Макеты = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПутьКМакету);
	РегистрыСведений.ПользовательскиеМакетыПечати.УстановитьИспользованиеИзмененныхМакетов(Макеты, Ложь);
	
КонецПроцедуры

// Возвращает табличный документ по двоичным данным табличного документа.
//
// Параметры:
//  ДвоичныеДанныеДокумента - ДвоичныеДанные - двоичные данные табличного документа.
//
// Возвращаемое значение:
//  ТабличныйДокумент - табличный документ.
//
Функция ТабличныйДокументПоДвоичнымДанным(ДвоичныеДанныеДокумента) Экспорт
	
	ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
	ДвоичныеДанныеДокумента.Записать(ИмяВременногоФайла);
	ТабличныйДокумент = Новый ТабличныйДокумент;
	ТабличныйДокумент.Прочитать(ИмяВременногоФайла);
	
	УстановленБезопасныйРежим = БезопасныйРежим();
	Если ТипЗнч(УстановленБезопасныйРежим) = Тип("Строка") Тогда
		УстановленБезопасныйРежим = Истина;
	КонецЕсли;
	
	Если Не УстановленБезопасныйРежим Тогда
		УдалитьФайлы(ИмяВременногоФайла);
	КонецЕсли;
	
	Возврат ТабличныйДокумент;
	
КонецФункции

// Формирует печатные формы в требуемом формате и записывает в файлы.
// Ограничение: печатные формы, формируемые на клиенте не поддерживаются.
//
// Параметры:
//  КомандыПечати  - Структура
//                 - Массив - команда или несколько команд печати формы,
//                            см. УправлениеПечатью.КомандыПечатиФормы.
//  СписокОбъектов - Массив    - ссылки на печатаемые объекты.
//  НастройкиСохранения - см. УправлениеПечатью.НастройкиСохранения.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * ИмяФайла - Строка - имя файла;
//   * ДвоичныеДанные - ДвоичныеДанные - файл печатной формы.
//
Функция НапечататьВФайл(КомандыПечати, СписокОбъектов, НастройкиСохранения) Экспорт
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("ИмяФайла", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("ДвоичныеДанные", Новый ОписаниеТипов("ДвоичныеДанные"));
	
	СписокКоманд = КомандыПечати;
	Если ТипЗнч(КомандыПечати) <> Тип("Массив") Тогда
		СписокКоманд = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(КомандыПечати);
	КонецЕсли;
	
	Для Каждого КомандаПечати Из СписокКоманд Цикл
		ВыполнитьКомандуПечатиВФайл(КомандаПечати, НастройкиСохранения, СписокОбъектов, Результат);
	КонецЦикла;
	
	Если ЗначениеЗаполнено(Результат) И НастройкиСохранения.УпаковатьВАрхив Тогда
		ДвоичныеДанные = УпаковатьВАрхив(Результат);
		Результат.Очистить();
		Файл = Результат.Добавить();
		Файл.ИмяФайла = ИмяФайла(ПолучитьИмяВременногоФайла("zip"));
		Файл.ДвоичныеДанные = ДвоичныеДанные;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Конструктор параметра НастройкиСохранения функции УправлениеПечатью.НапечататьВФайл.
// Определяет формат и другие настройки записи табличного документа в файл.
// 
// Возвращаемое значение:
//  Структура - настройки записи табличного документа в файл:
//   * ФорматыСохранения - Массив - коллекция значений типа ТипФайлаТабличногоДокумента,
//                                  либо значений типа ТипФайлаТабличногоДокумента, преобразованных в строку.
//                                  По умолчанию сохранение выполняется в формате PDF.
//   * УпаковатьВАрхив   - Булево - если установить значение Истина, будет создан один файл архива с файлами указанных форматов.
//   * ПереводитьИменаФайловВТранслит - Булево - если установить Истина, то имена полученных файлов будут на латинице.
//   * ПодписьИПечать    - Булево - если установить Истина и сохраняемый табличный документ поддерживает размещение
//                                  подписей и печатей, то в записанных файлах будут размещены подписи и печати.
//
Функция НастройкиСохранения() Экспорт
	
	Возврат УправлениеПечатьюКлиентСервер.НастройкиСохранения();
	
КонецФункции

// Определяет тип параметра Настройки в процедурах ПриОпределенииНастроекПечати модулей менеджеров объектов.
// Возвращает настройки печати объекта, подключенного к подсистеме печати.
//
// Параметры:
//  МенеджерОбъекта - СправочникМенеджер, ДокументМенеджер, ОбработкаМенеджер, РегистрСведенийМенеджер - менеджер объекта.
//
// Возвращаемое значение:
//  Структура:
//   * ПриОпределенииПолучателей - Булево - при установке значения Истина будет вызвана процедура модуля менеджера
//                                          объекта ПриОпределенииПолучателей,
//                                          где определяются получатели для отправки печатной формы.
//                                          По умолчанию, значение Ложь. 
//   * ПриДобавленииКомандПечати - Булево - при установке значения Истина будет вызвана процедура модуля
//                                          менеджера объекта ДобавитьКомандыПечати, где добавляются команды печати.
//                                          По умолчанию, значение Ложь. 
//
Функция НастройкиПечатиОбъекта(МенеджерОбъекта) Экспорт
	
	НастройкиОбъекта = Новый Структура;
	НастройкиОбъекта.Вставить("ПриОпределенииПолучателей", Ложь);
	НастройкиОбъекта.Вставить("ПриДобавленииКомандПечати", Ложь);
	
	НастройкиПечати = НастройкиПечати(); 
	
	Если НастройкиПечати.ОбъектыПечати.Найти(МенеджерОбъекта) <> Неопределено Тогда
		МенеджерОбъекта.ПриОпределенииНастроекПечати(НастройкиОбъекта);
		Возврат НастройкиОбъекта;
	КонецЕсли;
	
	// Поддержка обратной совместимости
	
	ОбъектыСКомандамиПечати = Новый Массив;
	
	СписокОбъектов = Новый Массив;
	ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовСКомандамиПечати(СписокОбъектов); // АПК:222 Вызов устаревшей процедуры для обратной совместимости.
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОбъектыСКомандамиПечати, СписокОбъектов, Истина);
	
	СписокОбъектов = Новый Массив;
	УправлениеПечатьюПереопределяемый.ПриОпределенииОбъектовСКомандамиПечати(СписокОбъектов); // АПК:222 Вызов устаревшей процедуры для обратной совместимости.
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОбъектыСКомандамиПечати, СписокОбъектов, Истина);
	
	Если ОбъектыСКомандамиПечати.Найти(МенеджерОбъекта) <> Неопределено Тогда
		НастройкиОбъекта.ПриДобавленииКомандПечати = Истина;
	КонецЕсли;
	
	Возврат НастройкиОбъекта;
	
КонецФункции

#Область РаботаСМакетамиОфисныхДокументов

////////////////////////////////////////////////////////////////////////////////
// Работа с макетами офисных документов.

//	Секция содержит интерфейсные функции (API), используемые при создании
//	печатных форм основанных на офисных документах. На данный момент поддерживается
//	офисные пакеты, работающие с форматом Office Open XML (MS Office, Open Office, Google Docs).
//
////////////////////////////////////////////////////////////////////////////////
//	Типы используемых данных (определяется конкретными реализациями).
//	СсылкаПечатнаяФорма	- ссылка на печатную форму.
//	СсылкаМакет			- ссылка на макет.
//	Область				- ссылка на область в печатной форме или макете (структура)
//						доопределяется в интерфейсном модуле служебной информацией
//						об области.
//	ОписаниеОбласти		- описание области макета (см. ниже).
//	ДанныеЗаполнения	- либо структура, либо массив структур (для случая
//						списков и таблиц.
////////////////////////////////////////////////////////////////////////////////
//	ОписаниеОбласти - структура, описывающая подготовленные пользователем области макета
//	ключ ИмяОбласти - имя области
//	ключ ТипТипОбласти - 	ВерхнийКолонтитул.
//							НижнийКолонтитул
//							ВерхнийТитульныйКолонтитул
//							НижнийТитульныйКолонтитул
//							ВерхнийЧетныйКолонтитул
//							НижнийЧетныйКолонтитул
//							Общая
//							СтрокаТаблицы
//							Список
//

////////////////////////////////////////////////////////////////////////////////
// Функции инициализации и закрытия ссылок.

// АПК:1382-выкл - Нельзя определять тип в возвращаемом значении.
//
// Конструктор печатной формы в формате офисного документа.
//
// Параметры:
//  УдалитьТипДокумента            - Строка - устаревший параметр, не используется;
//  УдалитьНастройкиСтраницыМакета - Соответствие - устаревший параметр, не используется;
//  Макет                          - см. ИнициализироватьМакетОфисногоДокумента
//
// Возвращаемое значение:
//  Структура - описание создаваемой печатной формы:
//   * ИмяКаталога        - Строка - путь, куда помещается структура каталогов конечного документа для последующей
//                                   сборки контейнера DOCX.
//   * СтруктураДокумента - см. УправлениеПечатьюСлужебный.ИнициализироватьДокумент
//   * Тип - Строка
//   * ПоследняяВыделеннаяОбласть - Структура
//
Функция ИнициализироватьПечатнуюФорму(Знач УдалитьТипДокумента, Знач УдалитьНастройкиСтраницыМакета = Неопределено, Макет = Неопределено) Экспорт
	
	Если Макет = Неопределено Тогда
		ВызватьИсключение НСтр("ru = 'Укажите значение параметра ""Макет""'");
	КонецЕсли;
	
	ПечатнаяФорма = УправлениеПечатьюСлужебный.ИнициализироватьПечатнуюФорму(Макет);
	ПечатнаяФорма.Вставить("Тип", "DOCX");
	ПечатнаяФорма.Вставить("ПоследняяВыведеннаяОбласть", Неопределено);
	
	Возврат ПечатнаяФорма;
	
КонецФункции
// АПК:1382-вкл

// Подготавливает макет для использования в процедурах формирования печатной формы.
//
// Параметры:
//  ДвоичныеДанныеМакета - ДвоичныеДанные - двоичные данные макета;
//  УдалитьТипМакета     - Строка - устаревший параметр, не используется;
//  УдалитьИмяМакета     - Строка - устаревший параметр, не используется.
//
// Возвращаемое значение:
//  Структура:
//   * ИмяКаталога        - Строка    - путь, куда распаковывается контейнер DOCX шаблона для дальнейшего анализа;
//   * СтруктураДокумента - Структура - информация по областям, разделам и колонтитулам, входящих в шаблон.
//
Функция ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета, Знач УдалитьТипМакета, Знач УдалитьИмяМакета = "") Экспорт
	
	Макет = УправлениеПечатьюСлужебный.МакетИзДвоичныхДанных(ДвоичныеДанныеМакета);
	Если Макет <> Неопределено Тогда
		Макет.Вставить("Тип", "DOCX");
		Макет.Вставить("НастройкиСтраницыМакета", Новый Соответствие);
	КонецЕсли;
	
	Возврат Макет;
	
КонецФункции


// Удаляет временные файлы, образовавшиеся после раскрытия xml-структуры макета.
// Необходимо вызывать каждый раз после завершения формирования макета и печатной формы,
// а также в случае аварийного завершения формирования.
//
// Параметры:
//  ПечатнаяФорма            - см. УправлениеПечатью.ИнициализироватьПечатнуюФорму
//  УдалитьЗакрытьПриложение - Булево    - устаревший параметр, не используется.
//
Процедура ОчиститьСсылки(ПечатнаяФорма, Знач УдалитьЗакрытьПриложение = Истина) Экспорт
	
	Если ПечатнаяФорма <> Неопределено Тогда
		УправлениеПечатьюСлужебный.ЗакрытьСоединение(ПечатнаяФорма);
		ПечатнаяФорма = Неопределено;
	КонецЕсли;
	
КонецПроцедуры

// Формирует файл выходной печатной формы и помещает его в хранилище.
// Необходимо вызывать после помещения в структуру печатной формы всех необходимых областей.
//
// Параметры:
//  ПечатнаяФорма - см. УправлениеПечатью.ИнициализироватьПечатнуюФорму.
//
// Возвращаемое значение:
//  Строка - адрес хранилища, куда помещается сформированный файл.
//
Функция СформироватьДокумент(Знач ПечатнаяФорма) Экспорт
	
	АдресХранилищаПечатнойФормы = УправлениеПечатьюСлужебный.СформироватьДокумент(ПечатнаяФорма);
	
	Возврат АдресХранилищаПечатнойФормы;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Функции получения областей из макета, вывода в печатную форму областей макета
// и заполнение параметров в них.

// Получает область из макета печатной формы.
//
// Параметры:
//   СсылкаНаМакет   - Структура - макет печатной формы.
//   ОписаниеОбласти - Структура:
//    * ИмяОбласти - Строка - имя области;
//    * ТипТипОбласти - Строка - тип области: 
//      "ВерхнийКолонтитул", "НижнийКолонтитул",
//      "ВерхнийТитульныйКолонтитул", "НижнийТитульныйКолонтитул",
//      "ВерхнийЧетныйКолонтитул", "НижнийЧетныйКолонтитул",
//      "Общая",
//      "СтрокаТаблицы", 
//      "Список".
//
// Возвращаемое значение:
//  Структура - область макета.
//
Функция ОбластьМакета(СсылкаНаМакет, ОписаниеОбласти) Экспорт
	
	Область = Неопределено;
	
	Если ОписаниеОбласти.ТипОбласти = "ВерхнийКолонтитул" Или ОписаниеОбласти.ТипОбласти = "ВерхнийЧетныйКолонтитул" 
		Или ОписаниеОбласти.ТипОбласти = "ВерхнийТитульныйКолонтитул" Тогда
		Область = УправлениеПечатьюСлужебный.ПолучитьОбластьВерхнегоКолонтитула(СсылкаНаМакет, ОписаниеОбласти.ИмяОбласти);
	ИначеЕсли ОписаниеОбласти.ТипОбласти = "НижнийКолонтитул"  Или ОписаниеОбласти.ТипОбласти = "НижнийЧетныйКолонтитул"  
		Или ОписаниеОбласти.ТипОбласти = "НижнийТитульныйКолонтитул" Тогда
		Область = УправлениеПечатьюСлужебный.ПолучитьОбластьНижнегоКолонтитула(СсылкаНаМакет, ОписаниеОбласти.ИмяОбласти);
	ИначеЕсли ОписаниеОбласти.ТипОбласти = "Общая" 
		Или ОписаниеОбласти.ТипОбласти = "СтрокаТаблицы"
		Или ОписаниеОбласти.ТипОбласти = "Список" Тогда
		Область = УправлениеПечатьюСлужебный.ПолучитьОбластьМакета(СсылкаНаМакет, ОписаниеОбласти.ИмяОбласти);
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Тип области не указан или указан некорректно: %1.'"), ОписаниеОбласти.ТипОбласти);
	КонецЕсли;
	
	Если Область <> Неопределено Тогда
		Область.Вставить("ОписаниеОбласти", ОписаниеОбласти);
	КонецЕсли;
	
	Возврат Область;
	
КонецФункции

// Присоединяет область в печатную форму из макета.
// Применяется при одиночном выводе области.
//
// Параметры:
//  ПечатнаяФорма - см. УправлениеПечатью.ИнициализироватьПечатнуюФорму.
//  ОбластьМакета - см. УправлениеПечатью.ОбластьМакета.
//  ПереходНаСледующуюСтроку - Булево - Истина, если требуется вставить разрыв после вывода области.
//
Процедура ПрисоединитьОбласть(ПечатнаяФорма, ОбластьМакета, Знач ПереходНаСледующуюСтроку = Ложь) Экспорт
	
	Если ОбластьМакета = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Попытка
		
		ОписаниеОбласти = ОбластьМакета.ОписаниеОбласти;
		ВыведеннаяОбласть = Неопределено;
		
		Если ОписаниеОбласти.ТипОбласти = "ВерхнийКолонтитул" Или ОписаниеОбласти.ТипОбласти = "ВерхнийЧетныйКолонтитул" 
			Или ОписаниеОбласти.ТипОбласти = "ВерхнийТитульныйКолонтитул" Тогда
				ВыведеннаяОбласть = УправлениеПечатьюСлужебный.ДобавитьВерхнийКолонтитул(ПечатнаяФорма, ОбластьМакета);
		ИначеЕсли ОписаниеОбласти.ТипОбласти = "НижнийКолонтитул"  Или ОписаниеОбласти.ТипОбласти = "НижнийЧетныйКолонтитул"
			Или ОписаниеОбласти.ТипОбласти = "НижнийТитульныйКолонтитул" Тогда
			ВыведеннаяОбласть = УправлениеПечатьюСлужебный.ДобавитьНижнийКолонтитул(ПечатнаяФорма, ОбластьМакета);
		ИначеЕсли ОписаниеОбласти.ТипОбласти = "Общая" Или ОписаниеОбласти.ТипОбласти = "Список" 
			Или ОписаниеОбласти.ТипОбласти = "СтрокаТаблицы" Тогда
			ВыведеннаяОбласть = УправлениеПечатьюСлужебный.ПрисоединитьОбласть(ПечатнаяФорма, ОбластьМакета, ПереходНаСледующуюСтроку);
		Иначе
			ВызватьИсключение ТекстТипОбластиУказанНекорректно();
		КонецЕсли;
		
		ОписаниеОбласти.Вставить("Область", ВыведеннаяОбласть);
		ОписаниеОбласти.Вставить("ПереходНаСледующуюСтроку", ПереходНаСледующуюСтроку);
		
		// Содержит тип и границы области (если требуется).
		ПечатнаяФорма.ПоследняяВыведеннаяОбласть = ОписаниеОбласти;
		
	Исключение
		СообщениеОбОшибке = СокрЛП(ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		СообщениеОбОшибке = ?(Прав(СообщениеОбОшибке, 1) = ".", СообщениеОбОшибке, СообщениеОбОшибке + ".");
		СообщениеОбОшибке = СообщениеОбОшибке + " " + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка при попытке вывести область ""%1"" из макета.'"),
			ОбластьМакета.ОписаниеОбласти.ИмяОбласти);
		ВызватьИсключение СообщениеОбОшибке;
	КонецПопытки;
	
КонецПроцедуры

// Заполняет параметры области печатной формы.
//
// Параметры:
//  ПечатнаяФорма - Структура - область печатной формы либо сама печатная форма.
//  Данные - Структура - данные заполнения.
//
Процедура ЗаполнитьПараметры(ПечатнаяФорма, Данные) Экспорт
	
	ОписаниеОбласти = ПечатнаяФорма.ПоследняяВыведеннаяОбласть; // см. ОбластьМакета.ОписаниеОбласти
	
	Если ОписаниеОбласти.ТипОбласти = "ВерхнийКолонтитул" ИЛИ ОписаниеОбласти.ТипОбласти = "ВерхнийЧетныйКолонтитул" ИЛИ ОписаниеОбласти.ТипОбласти = "ВерхнийТитульныйКолонтитул" Тогда
		УправлениеПечатьюСлужебный.ЗаполнитьПараметрыВерхнегоКолонтитула(ПечатнаяФорма, ОписаниеОбласти.Область, Данные);
	ИначеЕсли ОписаниеОбласти.ТипОбласти = "НижнийКолонтитул"  ИЛИ ОписаниеОбласти.ТипОбласти = "НижнийЧетныйКолонтитул"  ИЛИ ОписаниеОбласти.ТипОбласти = "НижнийТитульныйКолонтитул" Тогда
		УправлениеПечатьюСлужебный.ЗаполнитьПараметрыНижнегоКолонтитула(ПечатнаяФорма, ОписаниеОбласти.Область, Данные);
	ИначеЕсли ОписаниеОбласти.ТипОбласти = "Общая"
			ИЛИ ОписаниеОбласти.ТипОбласти = "СтрокаТаблицы"
			ИЛИ ОписаниеОбласти.ТипОбласти = "Список" Тогда
		УправлениеПечатьюСлужебный.ЗаполнитьПараметры(ПечатнаяФорма, ОписаниеОбласти.Область, Данные);
	Иначе
		ВызватьИсключение ТекстТипОбластиУказанНекорректно();
	КонецЕсли;

КонецПроцедуры

// Добавляет область в печатную форму из макета, при этом заменяя параметры в области значениями из данных объекта.
// Применяется при одиночном выводе области.
//
// Параметры:
//  ПечатнаяФорма - см. УправлениеПечатью.ИнициализироватьПечатнуюФорму.
//  ОбластьМакета - см. УправлениеПечатью.ОбластьМакета.
//  Данные - Структура - данные заполнения.
//  ПереходНаСледующуюСтроку - Булево - Истина, если требуется вставить разрыв после вывода области.
//
Процедура ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьМакета, Данные, Знач ПереходНаСледующуюСтроку = Ложь) Экспорт
	
	Если ОбластьМакета = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ПрисоединитьОбласть(ПечатнаяФорма, ОбластьМакета, ПереходНаСледующуюСтроку);
	ЗаполнитьПараметры(ПечатнаяФорма, Данные);
	
КонецПроцедуры

// Добавляет область в печатную форму из макета, при этом заменяя
// параметры в области значениями из данных объекта.
// Применяется при одиночном выводе области.
//
// Параметры:
//  ПечатнаяФорма - см. УправлениеПечатью.ИнициализироватьПечатнуюФорму.
//  ОбластьМакета - см. УправлениеПечатью.ОбластьМакета.
//  Данные - Массив - коллекция элементов типа Структура - данные объекта.
//  ПереходНаСледСтроку - Булево - Истина, если требуется вставить разрыв после вывода области.
//
Процедура ПрисоединитьИЗаполнитьКоллекцию(ПечатнаяФорма, ОбластьМакета, Данные, Знач ПереходНаСледСтроку = Ложь) Экспорт
	
	Если ОбластьМакета = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ОписаниеОбласти = ОбластьМакета.ОписаниеОбласти;
	
	Если ОписаниеОбласти.ТипОбласти = "СтрокаТаблицы" ИЛИ ОписаниеОбласти.ТипОбласти = "Список" Тогда
		УправлениеПечатьюСлужебный.ПрисоединитьИЗаполнитьНабор(ПечатнаяФорма, ОбластьМакета, Данные, ПереходНаСледСтроку);
	Иначе
		ВызватьИсключение ТекстТипОбластиУказанНекорректно();
	КонецЕсли;
	
КонецПроцедуры

// Вставляет разрыв между строками в виде символа перевода строки.
//
// Параметры:
//  ПечатнаяФорма - см. УправлениеПечатью.ИнициализироватьПечатнуюФорму.
//
Процедура ВставитьРазрывНаНовуюСтроку(ПечатнаяФорма) Экспорт
	
	УправлениеПечатьюСлужебный.ВставитьРазрывНаНовуюСтроку(ПечатнаяФорма);
	
КонецПроцедуры


#КонецОбласти

#Область УстаревшиеПроцедурыИФункции

// Локализация

// Устарела. Следует использовать УправлениеПечатьюРФ.ФорматнаяСтрокаУФЭБС.
//
// Формирует форматную строку согласно "Унифицированному формату электронных банковских сообщений" для ее отображения в
// виде QR-кода.
//
// Параметры:
//  ДанныеДокумента  - Структура - содержит значения полей документа.
//    Данные документа будут закодированы согласно стандарту 
//    "Стандарты финансовых операций. Символы двумерного штрихового кода для осуществления платежей физических лиц".
//    ДанныеДокумента должны содержать информацию в полях, описанных ниже.
//    Обязательные поля структуры:
//     * ТекстПолучателя             - Строка - наименование получателя платежа, макс. 160 символов;
//     * НомерСчетаПолучателя        - Строка - номер счета получателя платежа, макс. 20 символов;
//     * НаименованиеБанкаПолучателя - Строка - наименование банка получателя платежа, макс. 45 символов;
//     * БИКБанкаПолучателя          - Строка - макс. 9 символов;
//     * СчетБанкаПолучателя         - Строка - номер к/с банка получателя платежа, макс. 20 символов;
//    Дополнительные поля структуры:
//     * СуммаЧислом         - Строка - сумма платежа, в рублях, макс. 16 символов.
//     * НазначениеПлатежа   - Строка - наименование платежа (назначение), макс. 210 символов;
//     * ИННПолучателя       - Строка - ИНН получателя платежа, макс. 12 символов;
//     * ИННПлательщика      - Строка - ИНН плательщика, макс. 12 символов;
//     * СтатусСоставителя   - Строка - статус составителя платежного документа, макс. 2 символа;
//     * КПППолучателя       - Строка - КПП получателя платежа, макс. 9 символов.
//     * КодБК               - Строка - КБК, макс. 20 символов;
//     * КодОКТМО            - Строка - ОКТМО, макс. 11 символов;
//     * ПоказательОснования - Строка - основание налогового платежа, макс. 2 символа;
//     * ПоказательПериода   - Строка - налоговый период, макс. 10 символов;
//     * ПоказательНомера    - Строка - номер документа, макс. 15 символов;
//     * ПоказательДаты      - Строка - дата документа, макс. 10 символов.
//     * ПоказательТипа      - Строка - тип платежа, макс. 2 символа.
//    Прочие дополнительные поля:
//     * ФамилияПлательщика               - Строка - фамилия плательщика.
//     * ИмяПлательщика                   - Строка - имя плательщика.
//     * ОтчествоПлательщика              - Строка - отчество плательщика.
//     * АдресПлательщика                 - Строка - адрес плательщика.
//     * ЛицевойСчетБюджетногоПолучателя  - Строка - лицевой счет бюджетного получателя.
//     * ИндексПлатежногоДокумента        - Строка - индекс платежного документа.
//     * СНИЛС                            - Строка - № лицевого счета в системе персонифицированного учета в ПФР - СНИЛС.
//     * НомерДоговора                    - Строка - номер договора.
//     * НомерЛицевогоСчетаПлательщика    - Строка - номер лицевого счета плательщика в организации (в системе учета ПУ).
//     * НомерКвартиры                    - Строка - номер квартиры.
//     * НомерТелефона                    - Строка - номер телефона.
//     * ВидПлательщика                   - Строка - вид ДУЛ плательщика.
//     * НомерПлательщик                  - Строка - номер ДУЛ плательщика.
//     * ФИОРебенка                       - Строка - ФИО ребенка/учащегося.
//     * ДатаРождения                     - Строка - дата рождения.
//     * СрокПлатежа                      - Строка - срок платежа/дата выставления счета.
//     * ПериодОплаты                     - Строка - период оплаты.
//     * ВидПлатежа                       - Строка - вид платежа.
//     * КодУслуги                        - Строка - код услуги/название прибора учета.
//     * НомерПрибораУчета                - Строка - номер прибора учета.
//     * ПоказаниеПрибораУчета            - Строка - показание прибора учета.
//     * НомерИзвещения                   - Строка - номер извещения, начисления, счета.
//     * ДатаИзвещения                    - Строка - дата извещения/начисления/счета/постановления (для ГИБДД).
//     * НомерУчреждения                  - Строка - номер учреждения (образовательного, медицинского).
//     * НомерГруппы                      - Строка - номер группы детсада/класса школы.
//     * ФИОПреподавателя                 - Строка - ФИО преподавателя, специалиста, оказывающего услугу.
//     * СуммаСтраховки                   - Строка - сумма страховки/дополнительной услуги/Сумма пени (в копейках).
//     * НомерПостановления               - Строка - номер постановления (для ГИБДД).
//     * НомерИсполнительногоПроизводства - Строка - номер исполнительного производства.
//     * КодВидаПлатежа                   - Строка - код вида платежа (например, для платежей в адрес Росреестра).
//     * ИдентификаторНачисления          - Строка - уникальный идентификатор начисления.
//     * ТехническийКод                   - Строка - технический код, рекомендуемый для заполнения поставщиком услуг.
//                                          Может использоваться принимающей организацией для вызова соответствующей
//                                          обрабатывающей ИТ-системы.
//                                          Перечень значений кода представлен ниже.
//
//       Код назначения     Наименование назначения платежа
//       платежа.
//       
//          01              Мобильная связь, стационарный телефон.
//          02              Коммунальные услуги, ЖКХ.
//          03              ГИБДД, налоги, пошлины, бюджетные платежи.
//          04              Охранные услуги
//          05              Услуги, оказываемые УФМС.
//          06              ПФР
//          07              Погашение кредитов
//          08              Образовательные учреждения.
//          09              Интернет и ТВ
//          10              Электронные деньги
//          11              Отдых и путешествия.
//          12              Инвестиции и страхование.
//          13              Спорт и здоровье
//          14              Благотворительные и общественные организации.
//          15              Прочие услуги.
//
// Возвращаемое значение:
//   Строка - строка данных в формате УФЭБС.
//
Функция ФорматнаяСтрокаУФЭБС(ДанныеДокумента) Экспорт
	
	МодульУправлениеПечатьюРФ = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатьюРФ");
	Если МодульУправлениеПечатьюРФ <> Неопределено Тогда
		Возврат МодульУправлениеПечатьюРФ.ФорматнаяСтрокаУФЭБС(ДанныеДокумента);
	КонецЕсли;
	
	Возврат "";
	
КонецФункции

// Конец Локализация

// Устарела. Следует использовать ГенерацияШтрихкода.ДанныеQRКода 
// или ГенерацияШтрихкода.ИзображениеШтрихкода.
//
// Возвращает двоичные данные для формирования QR-кода.
//
// Параметры:
//  QRСтрока         - Строка - данные, которые необходимо разместить в QR-коде.
//
//  УровеньКоррекции - Число - уровень погрешности изображения, при котором данный QR-код все еще возможно 100%
//                             распознать.
//                     Параметр должен иметь тип целого и принимать одно из 4 допустимых значений:
//                     0 (7 % погрешности), 1 (15 % погрешности), 2 (25 % погрешности), 3 (35 % погрешности).
//
//  Размер           - Число - определяет длину стороны выходного изображения в пикселях.
//                     Если минимально возможный размер изображения больше этого параметра - код сформирован не будет.
//
// Возвращаемое значение:
//  ДвоичныеДанные  - буфер, содержащий байты PNG-изображения QR-кода.
// 
// Пример:
//  
//  // Выводим на печать QR-код, содержащий в себе информацию зашифрованную по УФЭБС.
//
//  QRСтрока = УправлениеПечатью.ФорматнаяСтрокаУФЭБС(РеквизитыПлатежа);
//  ТекстОшибки = "";
//  ДанныеQRКода = УправлениеПечатью.ДанныеQRКода(QRСтрока, 0, 190, ТекстОшибки);
//  Если Не ПустаяСтрока(ТекстОшибки)
//      ОбщегоНазначения.СообщитьПользователю(ТекстОшибки);
//  КонецЕсли;
//
//  КартинкаQRКода = Новый Картинка(ДанныеQRКода);
//  ОбластьМакета.Рисунки.QRКод.Картинка = КартинкаQRКода;
//
Функция ДанныеQRКода(QRСтрока, УровеньКоррекции, Размер) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГенерацияШтрихкода") Тогда
		МодульГенерацияШтрихкода = ОбщегоНазначения.ОбщийМодуль("ГенерацияШтрихкода");
		Возврат МодульГенерацияШтрихкода.ДанныеQRКода(QRСтрока, УровеньКоррекции, Размер);
	КонецЕсли;
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	ГенераторQRКода = КомпонентаФормированияQRКода();
	Если ГенераторQRКода = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Попытка
		ДвоичныеДанныеКартинки = ГенераторQRКода.GenerateQRCode(QRСтрока, УровеньКоррекции, Размер);
	Исключение
		ЗаписьЖурналаРегистрации(НСтр("ru = 'Формирование QR-кода'", ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
	Возврат ДвоичныеДанныеКартинки;
	
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

#Область РаботаСМакетамиОфисныхДокументовССКД


// Подготавливает макет офисного документа для использования в процедурах формирования печатной формы.
// 
// Параметры:
//  ДвоичныеДанныеМакета - ДвоичныеДанные - двоичные данные макета
// 
// Возвращаемое значение:
//   см. УправлениеПечатьюСлужебный.МакетИзДвоичныхДанныхСКД
//
Функция ИнициализироватьМакетОфисногоДокументаСКД(ДвоичныеДанныеМакета) Экспорт
	
	ДеревоМакета = УправлениеПечатьюСлужебный.МакетИзДвоичныхДанныхСКД(ДвоичныеДанныеМакета);
	СтруктураДокумента = ДеревоМакета.СтруктураДокумента;
	
	УзелНачалаТекста = УправлениеПечатьюСлужебный.ПолучитьУзел(СтруктураДокумента.ДеревоДокумента, "w:document/w:body");
	СобратьСтроки(УзелНачалаТекста);
	УправлениеПечатьюСлужебный.ВосстановитьПолныйТекст(СтруктураДокумента.ДеревоДокумента, СтруктураДокумента.Гиперссылки);
	
	Возврат ДеревоМакета;
	
КонецФункции

// Размещает штампы в переданном офисный документ.
// 
// Параметры:
//  АдресДокумента - Строка - адрес документа во временном хранилище
//  ЭлектронныеПодписи - см. ЭлектроннаяПодпись.УстановленныеПодписи
//  
Процедура ДобавитьШтампыВОфисныйДокумент(АдресДокумента, ЭлектронныеПодписи) Экспорт
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресДокумента);
	ДеревоМакета = ИнициализироватьМакетОфисногоДокументаСКД(ДвоичныеДанные);
	СтруктураДокумента = ДеревоМакета.СтруктураДокумента;
	
	МакетШтампа = ПолучитьОбщийМакет("МакетШтемпеляЭЦПOfficeOpen");
	ТекстМакетаШтампа = МакетШтампа.ПолучитьТекст();
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ИгнорироватьПробелы = Истина;
	ЧтениеXML.УстановитьСтроку(ТекстМакетаШтампа);
	
	ДеревоМакетаШтампа = УправлениеПечатьюСлужебный.ПрочитатьXMLВДерево(ЧтениеXML);
	УдалитьНезначащиеАтрибуты(ДеревоМакетаШтампа);
	
	УзелДокумента = ДеревоМакетаШтампа.Строки[0];
	УзелШтампа = УзелДокумента.Строки[0];
	
	МассивЗакладок = Новый Массив;
	ПараметрыПоискаУзлов = УправлениеПечатьюСлужебный.ПараметрыПоискаУзлов();
	ПараметрыПоискаУзлов.ИмяАтрибута = "w:name";
	ПараметрыПоискаУзлов.ЗначенияАтрибута = "V8DSStamp";
	УправлениеПечатьюСлужебный.НайтиУзлыПоСодержимому(СтруктураДокумента.ДеревоДокумента, "w:bookmarkStart", МассивЗакладок, ПараметрыПоискаУзлов);
	
	Если Не МассивЗакладок.Количество() Тогда
		Возврат;
	КонецЕсли;
	
	УзелЗакладкиШтампа = МассивЗакладок[МассивЗакладок.ВГраница()];
	РодительУзлаШтампа = УзелЗакладкиШтампа;
	
	УправлениеПечатьюСлужебный.ПеренестиПараметрыФорматирования(УзелШтампа, УзелЗакладкиШтампа);
	 
	ИндексРазмещения = Неопределено;
	УправлениеПечатьюСлужебный.НайтиУзелРазмещенияШтампа(РодительУзлаШтампа, ИндексРазмещения);
	
	
	ЗначенияДляЗаполнения = Новый Соответствие;
	ЗначенияДляЗаполнения.Вставить("[Заголовок]", НСтр("ru = 'ДОКУМЕНТ ПОДПИСАН ЭЛЕКТРОННОЙ ПОДПИСЬЮ'"));
	ЗначенияДляЗаполнения.Вставить("[ЗаголовокСертификат]", "Сертификат");
	ЗначенияДляЗаполнения.Вставить("[ЗаголовокВладелец]", "Владелец");
	ЗначенияДляЗаполнения.Вставить("[ЗаголовокПериодДействия]", "Действителен");
	
	Для Каждого Подпись Из ЭлектронныеПодписи Цикл
		Сертификат = Подпись.Сертификат;
		СертификатКриптографии = Новый СертификатКриптографии(Сертификат.Получить());
		
		ЗначенияДляЗаполнения.Вставить("[Владелец]", Подпись.КомуВыданСертификат);
		ЗначенияДляЗаполнения.Вставить("[Сертификат]", СертификатКриптографии.СерийныйНомер);
		
		ПериодДействия = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'с %1 по %2'"),
			Формат(СертификатКриптографии.ДатаНачала, "ДЛФ=D"), 
			Формат(СертификатКриптографии.ДатаОкончания, "ДЛФ=D"));
			
		ЗначенияДляЗаполнения.Вставить("[ПериодДействия]", ПериодДействия);
		
		ИндексРазмещения = ИндексРазмещения + 1;
		УзелРазмещенияШтампа = УправлениеПечатьюСлужебный.СкопироватьУзел(РодительУзлаШтампа, ИндексРазмещения, УзелШтампа);
		УправлениеПечатьюСлужебный.СоздатьПоследующие(УзелРазмещенияШтампа, УзелШтампа);
		УстановитьПараметрыВДереве(ЗначенияДляЗаполнения, УзелРазмещенияШтампа, ДеревоМакета);
	КонецЦикла;
	ПутьКДокументу = УправлениеПечатьюСлужебный.СобратьФайлОфисногоДокумента(ДеревоМакета);
	ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКДокументу);
	УдалитьФайлы(ПутьКДокументу);
	УдалитьФайлы(ДеревоМакета.ИмяКаталога);
	ПоместитьВоВременноеХранилище(ДвоичныеДанные, АдресДокумента);
КонецПроцедуры

// Преобразует параметры Office Open XML, в текст в квадратных скобках.
// 
// Параметры:
//  Дерево - см. УправлениеПечатьюСлужебный.ПрочитатьXMLВДерево
//
Процедура КонвертироватьПараметры(Дерево) Экспорт

	УправлениеПечатьюСлужебный.КонвертироватьПараметры(Дерево);
	
КонецПроцедуры


// Удаляет из дерева значений неиспользуемые атрибуты.
// 
// Параметры:
//  Дерево - см. УправлениеПечатьюСлужебный.ПрочитатьXMLВДерево
//
Процедура УдалитьНезначащиеАтрибуты(Дерево) Экспорт
	
	НезначащиеАтрибуты = СтрРазделить("w:rsidR,w:rsidRPr,w:rsidRDefault,w:rsidP,w:rsidTr", ",");
	УправлениеПечатьюСлужебный.УдалитьНезначащиеАтрибуты(Дерево, НезначащиеАтрибуты);
	
КонецПроцедуры

// Параметры заполнения области.
// 
// Возвращаемое значение:
//  Структура - параметры заполнения области:
//   * СобратьСтроки - Булево - собрать разбитые строки условий 
//   * СтруктураОбласти - см. УправлениеПечатьюСлужебный.ПрочитатьXMLВДерево
//   * ЗаполнятьКолонтитулы - Булево
//   * ДобавлятьСвязи - Булево - добавлять связи контента
//
Функция ПараметрыЗаполненияОбласти() Экспорт
	СтруктураПараметров = Новый Структура;
	СтруктураПараметров.Вставить("СобратьСтроки",  Истина); 
	СтруктураПараметров.Вставить("СтруктураОбласти", Неопределено); 
	СтруктураПараметров.Вставить("ЗаполнятьКолонтитулы", Истина); 
	СтруктураПараметров.Вставить("ДобавлятьСвязи", Истина);
	Возврат СтруктураПараметров;
КонецФункции

// Установить параметры.
// 
// Параметры:
//  ДеревоМакета -  см. УправлениеПечатьюСлужебный.ПрочитатьXMLВДерево
//  СоответствиеЗамен - Соответствие из КлючИЗначение - содержит правила перестановки
//  ПараметрыЗаполненияОбласти - см. ПараметрыЗаполненияОбласти
//
Процедура УстановитьПараметры(ДеревоМакета, СоответствиеЗамен, ПараметрыЗаполненияОбласти) Экспорт
	
	СобратьСтроки = ПараметрыЗаполненияОбласти.СобратьСтроки;
	СтруктураОбласти = ПараметрыЗаполненияОбласти.СтруктураОбласти;
	ЗаполнятьКолонтитулы = ПараметрыЗаполненияОбласти.ЗаполнятьКолонтитулы;
	ДобавлятьСвязи = ПараметрыЗаполненияОбласти.ДобавлятьСвязи;
	
	СтруктураДокумента = ДеревоМакета.СтруктураДокумента;
	ДеревоДокумента = ?(СтруктураОбласти = Неопределено, СтруктураДокумента.ДеревоДокумента, СтруктураОбласти.ДеревоОбласти);
	
	Если СобратьСтроки Тогда
		ПодготовитьУзлыУсловныхОбластей(ДеревоДокумента, СтруктураДокумента.Гиперссылки);
	КонецЕсли;
	
	Если ЗаполнятьКолонтитулы Тогда
		Для Каждого Колонтитул Из СтруктураДокумента.Колонтитулы Цикл
			УстановитьПараметрыВДереве(СоответствиеЗамен, Колонтитул.Значение, ДеревоМакета, ДобавлятьСвязи);
		КонецЦикла;
	КонецЕсли;
		
	УстановитьПараметрыВДереве(СоответствиеЗамен, ДеревоДокумента, ДеревоМакета, ДобавлятьСвязи);
	
КонецПроцедуры

#КонецОбласти

// Возвращает таблицу возможных форматов для сохранения табличного документа.
//
// Возвращаемое значение
//  ТаблицаЗначений:
//    * ТипФайлаТабличногоДокумента - ТипФайлаТабличногоДокумента - значение, соответствующее формату.
//    * Ссылка                      - ПеречислениеСсылка.ФорматыСохраненияОтчетов
//    * Представление               - Строка - представление типа файла (заполняется из перечисления).
//    * Расширение                  - Строка - тип файла для операционной системы.
//    * Картинка                    - Картинка - значок формата.
//
Функция НастройкиФорматовСохраненияТабличногоДокумента() Экспорт
	
	Возврат СтандартныеПодсистемыСервер.НастройкиФорматовСохраненияТабличногоДокумента();
	
КонецФункции

// Скрывает команды печати из подменю "Печать".
Процедура ОтключитьКомандыПечати(СписокОбъектов, СписокКоманд) Экспорт
	
	НаборЗаписей = РегистрыСведений.НастройкиКомандПечати.СоздатьНаборЗаписей();
	
	Для Каждого Объект Из СписокОбъектов Цикл
		КомандыПечатиОбъекта = СтандартныеКомандыПечатиОбъекта(Объект);
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НастройкиКомандПечати");
		ЭлементБлокировки.УстановитьЗначение("Владелец", Объект);
		
		НачатьТранзакцию();
		Попытка
			Блокировка.Заблокировать();
			
			Для Каждого ИдентификаторЗаменяемойКоманды Из СписокКоманд Цикл
				Отбор = Новый Структура;
				Отбор.Вставить("Идентификатор", ИдентификаторЗаменяемойКоманды);
				Отбор.Вставить("ФорматСохранения", "");
				Отбор.Вставить("СразуНаПринтер", Ложь);
				Отбор.Вставить("Отключена", Ложь);
				
				СписокЗаменяемыхКоманд = КомандыПечатиОбъекта.НайтиСтроки(Отбор);
				Для Каждого ЗаменяемаяКоманда Из СписокЗаменяемыхКоманд Цикл
					НаборЗаписей.Отбор.Владелец.Установить(Объект);
					НаборЗаписей.Отбор.УникальныйИдентификатор.Установить(ЗаменяемаяКоманда.УникальныйИдентификатор);
					НаборЗаписей.Прочитать();
					НаборЗаписей.Очистить();
					Если НаборЗаписей.Количество() = 0 Тогда
						Запись = НаборЗаписей.Добавить();
					Иначе
						Запись = НаборЗаписей[0];
					КонецЕсли;
					Запись.Владелец = Объект;
					Запись.УникальныйИдентификатор = ЗаменяемаяКоманда.УникальныйИдентификатор;
					Запись.Видимость = Ложь;
					НаборЗаписей.Записать();
				КонецЦикла;
			КонецЦикла;
			
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЦикла;
	
КонецПроцедуры

// Возвращает список поставляемых команд печати объекта.
//
// Параметры:
//  Объект - СправочникСсылка.ИдентификаторыОбъектовМетаданных
// 
// Возвращаемое значение:
//   см. СоздатьКоллекциюКомандПечати
//
Функция СтандартныеКомандыПечатиОбъекта(Объект) Экспорт
	
	КомандыПечатиОбъекта = КомандыПечатиОбъекта(
		ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору(Объект, Ложь));
		
	ВнешниеКомандыПечати = КомандыПечатиОбъекта.НайтиСтроки(Новый Структура("МенеджерПечати", "СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки"));
	Для Каждого КомандаПечати Из ВнешниеКомандыПечати Цикл
		КомандыПечатиОбъекта.Удалить(КомандаПечати);
	КонецЦикла;
	
	Возврат КомандыПечатиОбъекта;
КонецФункции

// Возвращает список объектов метаданных, в которых внедрена подсистема Печать.
//
// Возвращаемое значение:
//  Массив - список из элементов типа ОбъектМетаданных.
//
Функция ИсточникиКомандПечати() Экспорт
	ОбъектыСКомандамиПечати = Новый Массив;
	
	Настройки = НастройкиПечати();
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОбъектыСКомандамиПечати, Настройки.ОбъектыПечати, Истина);

	СписокОбъектов = Новый Массив;
	ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовСКомандамиПечати(СписокОбъектов); // АПК:222 Вызов устаревшей процедуры для обратной совместимости.
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОбъектыСКомандамиПечати, СписокОбъектов, Истина);
	
	СписокОбъектов = Новый Массив;
	УправлениеПечатьюПереопределяемый.ПриОпределенииОбъектовСКомандамиПечати(СписокОбъектов); // АПК:222 Вызов устаревшей процедуры для обратной совместимости.
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ОбъектыСКомандамиПечати, СписокОбъектов, Истина);
	
	Результат = Новый Массив;
	Для Каждого ОбъектМенеджер Из ОбъектыСКомандамиПечати Цикл
		Результат.Добавить(Метаданные.НайтиПоТипу(ТипЗнч(ОбъектМенеджер)));
	КонецЦикла;
	
	Возврат Результат;
КонецФункции


// Определяет объекты конфигурации, в модулях менеджеров которых размещена процедура ПриОпределенииНастроекПечати,
// определяющая наличие процедур подсистемы см. УправлениеПечатью.НастройкиПечатиОбъекта.
//
// Параметры:
//  Настройки - Структура:
//   * ИспользоватьПодписиИПечати - Булево - при установке значения Ложь отключается возможность установки подписей 
//                                           и печатей в печатных формах.
//   * СкрыватьПодписиИПечатиДляРедактирования - Булево - удалять рисунки подписей и печатей табличных документов при
//                                           снятии флажка "Подписи и печати" в форме "Печать документов", для того,
//                                           чтобы они не мешали редактировать текст, находящийся под ними.
//   * ОбъектыПечати - Массив - менеджеры объектов с процедурой ПриОпределенииНастроекПечати 
//   * ПроверкаПроведенияПередПечатью    - Булево - признак необходимости проверки проведенности
//                                        документов перед печатью, является значением по умолчанию для команды печати
//                                        см. УправлениеПечатью.СоздатьКоллекциюКомандПечати.
//                                        Для непроведенных документов команда печати не выполняется.
//                                        Если параметр не указан, то проверка проведенности не выполняется.
//
Функция НастройкиПечати() Экспорт
	
	Настройки = Новый Структура;
	Настройки.Вставить("ИспользоватьПодписиИПечати", Истина);
	Настройки.Вставить("СкрыватьПодписиИПечатиДляРедактирования", Ложь);
	Настройки.Вставить("ОбъектыПечати", Новый Массив);
	Настройки.Вставить("ПроверкаПроведенияПередПечатью", Ложь);
	
	ИнтеграцияПодсистемБСП.ПриОпределенииНастроекПечати(Настройки);
	УправлениеПечатьюПереопределяемый.ПриОпределенииНастроекПечати(Настройки);
	
	Возврат Настройки;
	
КонецФункции

Функция КомандыПечатиОбъектаДоступныеДляВложений(ОбъектМетаданных) Экспорт
	
	Если ИсточникиКомандПечати().Найти(ОбъектМетаданных) <> Неопределено Тогда
		Возврат КомандыПечатиОбъекта(ОбъектМетаданных);
	КонецЕсли;
	
	Возврат СоздатьКоллекциюКомандПечати();
	
КонецФункции

Процедура ЗаписатьМакетыНаДополнительныхЯзыках(ПараметрыМакета) Экспорт
	
	ИдентификаторКопируемогоМакета  = ПараметрыМакета.ИдентификаторКопируемогоМакета;
	ТекущийЯзык						= ПараметрыМакета.ТекущийЯзык;
	УникальныйИдентификатор			= ПараметрыМакета.УникальныйИдентификатор;
	ИдентификаторМакета				= ПараметрыМакета.ИдентификаторМакета;
	ВладелецМакета					= ПараметрыМакета.ВладелецМакета;
	ИмяДокумента					= ПараметрыМакета.ИмяДокумента;
	СсылкаМакета					= ПараметрыМакета.СсылкаМакета;
	ТипМакета						= ПараметрыМакета.ТипМакета;
	
	Если ИдентификаторКопируемогоМакета = "" Тогда
		Возврат;
	КонецЕсли;
	
	МассивСловИдентификатора = СтрРазделить(ИдентификаторКопируемогоМакета, ".", Ложь);
	Если МассивСловИдентификатора.Количество() > 1 Тогда
		ИдентификаторКопируемогоМакета = "";	
		ИмяКопируемогоМакета = МассивСловИдентификатора[МассивСловИдентификатора.ВГраница()];
		МассивСловИдентификатора.Удалить(МассивСловИдентификатора.ВГраница());
		ИмяКопируемогоОбъекта = СтрСоединить(МассивСловИдентификатора, ".");
		
		ТекстЗапроса = 
		"ВЫБРАТЬ
		|	ПользовательскиеМакетыПечати.Макет,
		|	ПользовательскиеМакетыПечати.ИмяМакета,
		|	"""" КАК КодЯзыка
		|ИЗ
		|	РегистрСведений.ПользовательскиеМакетыПечати КАК ПользовательскиеМакетыПечати
		|ГДЕ
		|	ПользовательскиеМакетыПечати.Объект = &Объект
		|	И ПользовательскиеМакетыПечати.ИмяМакета ПОДОБНО &ИмяМакета
		|	И ПользовательскиеМакетыПечати.Использование";
		
		Запрос = Новый Запрос(ТекстЗапроса);
		Запрос.Параметры.Вставить("Объект", ИмяКопируемогоОбъекта);
		Запрос.Параметры.Вставить("ИмяМакета", ИмяКопируемогоМакета + "_%");
	Иначе
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	МакетыПечатныхФормПредставления.Макет,
		|	МакетыПечатныхФормПредставления.КодЯзыка
		|ИЗ
		|	Справочник.МакетыПечатныхФорм.Представления КАК МакетыПечатныхФормПредставления
		|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.МакетыПечатныхФорм КАК МакетыПечатныхФорм
		|		ПО МакетыПечатныхФормПредставления.Ссылка = МакетыПечатныхФорм.Ссылка
		|ГДЕ
		|	МакетыПечатныхФорм.Идентификатор = &Идентификатор
		|	И МакетыПечатныхФормПредставления.КодЯзыка <> &КодЯзыка";
		
		Запрос = Новый Запрос(ТекстЗапроса);
		УникальныйИдентификаторКопируемогоМакета = Справочники.МакетыПечатныхФорм.ИдентификаторМакета(ИдентификаторКопируемогоМакета);
		Запрос.УстановитьПараметр("Идентификатор", УникальныйИдентификаторКопируемогоМакета);
		Запрос.УстановитьПараметр("КодЯзыка", ТекущийЯзык);
	КонецЕсли;
	
	Результат = Запрос.Выполнить();
	Выборка = Результат.Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		Если Выборка.КодЯзыка = "" Тогда
			МассивСловИмениМакета = СтрРазделить(Выборка.ИмяМакета, "_");
			КодЯзыкаМакета = МассивСловИмениМакета[МассивСловИмениМакета.ВГраница()];
			Если КодЯзыкаМакета = ТекущийЯзык Тогда
				Продолжить;
			КонецЕсли;
		Иначе
			КодЯзыкаМакета = Выборка.КодЯзыка;
		КонецЕсли;
		
		АдресМакетаВоВременномХранилище = ПоместитьВоВременноеХранилище(Выборка.Макет.Получить(), УникальныйИдентификатор);
		
		ОписаниеМакета = ОписаниеМакета();
		ОписаниеМакета.ИмяОбъектаМетаданныхМакета = ИдентификаторМакета;
		ОписаниеМакета.АдресМакетаВоВременномХранилище = АдресМакетаВоВременномХранилище;
		ОписаниеМакета.КодЯзыка = КодЯзыкаМакета;
		ОписаниеМакета.Владелец = ВладелецМакета;
		ОписаниеМакета.Наименование = ИмяДокумента;
		ОписаниеМакета.Ссылка = СсылкаМакета;
		ОписаниеМакета.ТипМакета = ТипМакета;
		
		ЗаписатьМакет(ОписаниеМакета);
		
	КонецЦикла;
	
КонецПроцедуры

Функция СформироватьПечатныеФормыВФоне(ПараметрыФоновойПечати) Экспорт
	
	ИменаМакетов = ПараметрыФоновойПечати.ИменаМакетов;
	ПараметрыВывода = ПараметрыФоновойПечати.ПараметрыВывода;
	ТекущийЯзык = ПараметрыФоновойПечати.ТекущийЯзык;
	ОбъектыПечати = ПараметрыФоновойПечати.ОбъектыПечати;
	ПараметрыПечати = ПараметрыФоновойПечати.ПараметрыПечати;
	СодержимоеХранилищ = ПараметрыФоновойПечати.СодержимоеХранилищ;
	УникальныйИдентификаторХранилища = ПараметрыФоновойПечати.УникальныйИдентификаторХранилища;
	ПоместитьВХранилища(ПараметрыПечати, СодержимоеХранилищ, УникальныйИдентификаторХранилища);
	ПараметрыФоновойПечати.Удалить("СодержимоеХранилищ");
	
	Результат = Неопределено;
	// Формирование табличных документов.
	Если ЗначениеЗаполнено(ПараметрыФоновойПечати.ИсточникДанных) Тогда
		Если ТипЗнч(ПараметрыВывода) = Тип("Структура") И ПараметрыВывода.Свойство("КодЯзыка") Тогда
			ПараметрыВывода.КодЯзыка = ТекущийЯзык;
		КонецЕсли;
		ПечатьПоВнешнемуИсточнику(
			ПараметрыФоновойПечати.ИсточникДанных,
			ПараметрыФоновойПечати.ПараметрыИсточника,
			Результат,
			ОбъектыПечати,
			ПараметрыВывода);
	Иначе
		ТипыОбъектовПечати = Новый Массив;
		ПараметрыПечати.Свойство("ТипыОбъектовПечати", ТипыОбъектовПечати);
		
		ДополнительныеПараметры = Неопределено;
		ПараметрыПечати.Свойство("ДополнительныеПараметры", ДополнительныеПараметры);
		
		ПечатныеФормы = СформироватьПечатныеФормы(ПараметрыФоновойПечати.ИмяМенеджераПечати, ИменаМакетов,
			ПараметрыФоновойПечати.ПараметрКоманды, ДополнительныеПараметры, ТипыОбъектовПечати, ТекущийЯзык);
		ОбъектыПечати = ПечатныеФормы.ОбъектыПечати;
		ПараметрыВывода = ПечатныеФормы.ПараметрыВывода;
		Результат = ПечатныеФормы.КоллекцияПечатныхФорм;
	КонецЕсли;
	
	// Установка признака сохранения печатной формы в файл (не открывать форму, сразу сохранять в файл).
	Если ТипЗнч(ПараметрыПечати) = Тип("Структура") И ПараметрыПечати.Свойство("ФорматСохранения")
		И ЗначениеЗаполнено(ПараметрыПечати.ФорматСохранения) Тогда
		НайденныйФормат = НастройкиФорматовСохраненияТабличногоДокумента().Найти(ТипФайлаТабличногоДокумента[ПараметрыПечати.ФорматСохранения], "ТипФайлаТабличногоДокумента");
		Если НайденныйФормат <> Неопределено Тогда
			НастройкиФорматаСохранения = Новый Структура("ТипФайлаТабличногоДокумента,Представление,Расширение,Фильтр");
			ЗаполнитьЗначенияСвойств(НастройкиФорматаСохранения, НайденныйФормат);
			НастройкиФорматаСохранения.Фильтр = НастройкиФорматаСохранения.Представление + "|*." + НастройкиФорматаСохранения.Расширение;
			НастройкиФорматаСохранения.ТипФайлаТабличногоДокумента = ПараметрыПечати.ФорматСохранения;
		КонецЕсли;
	КонецЕсли;
	
	РезультатФормирования = Новый Структура("КоллекцияПечатныхФорм,ПараметрыФоновогоЗадания,ОфисныеДокументы,
	|ОбъектыПечати,ПараметрыВывода,ПараметрыПечати,Сообщения");
	РезультатФормирования.ПараметрыВывода = ПараметрыВывода;
	РезультатФормирования.ПараметрыФоновогоЗадания = ПараметрыФоновойПечати;
	РезультатФормирования.ПараметрыПечати = ПараметрыПечати; 
	ОфисныеДокументы = Новый Соответствие();
	
	Для Каждого СтрокаРезультата Из Результат Цикл
		Если ЗначениеЗаполнено(СтрокаРезультата.ОфисныеДокументы) Тогда
			СтрокаРезультата.ОфисныеДокументы.Удалить(Неопределено);
			Для Каждого ОфисныйДокумент Из СтрокаРезультата.ОфисныеДокументы Цикл
				ОфисныеДокументы.Вставить(ОфисныйДокумент.Ключ, ПолучитьИзВременногоХранилища(ОфисныйДокумент.Ключ));
			КонецЦикла;
			Если СтрокаРезультата.ОфисныеДокументы.Количество() = 0 Тогда
				СтрокаРезультата.ОфисныеДокументы = Неопределено;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	РезультатФормирования.КоллекцияПечатныхФорм = ОбщегоНазначения.ТаблицаЗначенийВМассив(Результат);
	
	РезультатФормирования.ОфисныеДокументы = ОфисныеДокументы;
	РезультатФормирования.ОбъектыПечати = ОбъектыПечати;
	РезультатФормирования.Сообщения = ПолучитьСообщенияПользователю();	
	
	Возврат РезультатФормирования;
	
КонецФункции

// Формирует печатную форму по внешнему источнику.
//
// Параметры:
//   ДополнительнаяОбработкаСсылка - СправочникСсылка.ДополнительныеОтчетыИОбработки - внешняя обработка.
//   ПараметрыИсточника            - Структура:
//       * ИдентификаторКоманды - Строка - список макетов, перечисленных через запятую.
//       * ОбъектыНазначения    - Массив
//   КоллекцияПечатныхФорм - см. описание процедуры Печать() в документации.
//   ОбъектыПечати         - СписокЗначений  - см. описание процедуры Печать() в документации.
//   ПараметрыВывода       - Структура       - см. описание процедуры Печать() в документации.
//   
Процедура ПечатьПоВнешнемуИсточнику(ДополнительнаяОбработкаСсылка, ПараметрыИсточника, КоллекцияПечатныхФорм,
	ОбъектыПечати, ПараметрыВывода) Экспорт
	
	МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
	ВнешняяОбработкаОбъект = МодульДополнительныеОтчетыИОбработки.ОбъектВнешнейОбработки(ДополнительнаяОбработкаСсылка);
	Если ВнешняяОбработкаОбъект = Неопределено Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Внешняя обработка ""%1"" (тип ""%2"") не обслуживается.'"),
			Строка(ДополнительнаяОбработкаСсылка),
			Строка(ТипЗнч(ДополнительнаяОбработкаСсылка)));
	КонецЕсли;
	
	КоллекцияПечатныхФорм = ПодготовитьКоллекциюПечатныхФорм(ПараметрыИсточника.ИдентификаторКоманды);
	Если Не ЗначениеЗаполнено(ПараметрыВывода) Тогда
		ПараметрыВывода = ПодготовитьСтруктуруПараметровВывода();
	КонецЕсли;
	ПараметрыВывода.Вставить("ДополнительнаяОбработкаСсылка", ДополнительнаяОбработкаСсылка);
	
	ВнешняяОбработкаОбъект.Печать(
		ПараметрыИсточника.ОбъектыНазначения,
		КоллекцияПечатныхФорм,
		ОбъектыПечати,
		ПараметрыВывода);
	
	// Проверим, все ли макеты были сформированы.
	Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
		Если Не ПечатнаяФорма.ОфисныеДокументы = Неопределено Тогда
			ПечатнаяФорма.ТабличныйДокумент = Новый ТабличныйДокумент;
		КонецЕсли;
			
		Если ПечатнаяФорма.ТабличныйДокумент = Неопределено Тогда
			ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'В обработчике печати не был сформирован табличный документ для: %1'"),
				ПечатнаяФорма.ИмяМакета);
			ВызватьИсключение(ТекстСообщенияОбОшибке);
		КонецЕсли;
		
		ПечатнаяФорма.ТабличныйДокумент.КоличествоЭкземпляров = ПечатнаяФорма.Экземпляров;
		
		Если Не МакетСуществует(ПечатнаяФорма.ПолныйПутьКМакету) Тогда
			ПечатнаяФорма.ПолныйПутьКМакету = "";
		КонецЕсли;
		
		ПечатнаяФорма.Защита = ПечатнаяФорма.ТабличныйДокумент.Защита;
	КонецЦикла;
	
КонецПроцедуры

// См. ПодключаемыеКомандыПереопределяемый.ПриОпределенииСоставаНастроекПодключаемыхОбъектов
Процедура ПриОпределенииСоставаНастроекПодключаемыхОбъектов(НастройкиПрограммногоИнтерфейса) Экспорт
	Настройка = НастройкиПрограммногоИнтерфейса.Добавить();
	Настройка.Ключ          = "ДобавитьКомандыПечати";
	Настройка.ОписаниеТипов = Новый ОписаниеТипов("Булево");
КонецПроцедуры

// См. ПодключаемыеКомандыПереопределяемый.ПриОпределенииВидовПодключаемыхКоманд
Процедура ПриОпределенииВидовПодключаемыхКоманд(ВидыПодключаемыхКоманд) Экспорт
	Вид = ВидыПодключаемыхКоманд.Добавить();
	Вид.Имя         = "Печать";
	Вид.ИмяПодменю  = "ПодменюПечать";
	Вид.Заголовок   = НСтр("ru = 'Печать'");
	Вид.Порядок     = 40;
	Вид.Картинка    = БиблиотекаКартинок.Печать;
	Вид.Отображение = ОтображениеКнопки.КартинкаИТекст;
КонецПроцедуры

// См. ПодключаемыеКомандыПереопределяемый.ПриОпределенииКомандПодключенныхКОбъекту
Процедура ПриОпределенииКомандПодключенныхКОбъекту(НастройкиФормы, Источники, ПодключенныеОтчетыИОбработки, Команды) Экспорт
	
	СписокОбъектов = Новый Массив;
	Для Каждого Источник Из Источники.Строки Цикл
		СписокОбъектов.Добавить(Источник.Метаданные);
	КонецЦикла;
	Если Источники.Строки.Количество() = 1 И ОбщегоНазначения.ЭтоЖурналДокументов(Источники.Строки[0].Метаданные) Тогда
		СписокОбъектов = Неопределено;
	КонецЕсли;
	
	КомандыПечати = КомандыПечатиФормы(НастройкиФормы.ИмяФормы, СписокОбъектов);
	
	КлючиПараметровОбработчика = "Обработчик, МенеджерПечати, ЗаголовокФормы, СразуНаПринтер, ФорматСохранения,
	|ПереопределитьПользовательскиеНастройкиКоличества, ДополнитьКомплектВнешнимиПечатнымиФормами,
	|ФиксированныйКомплект, ДополнительныеПараметры, ВыполнятьВФоновомЗадании";
	Для Каждого КомандаПечати Из КомандыПечати Цикл
		Если КомандаПечати.Отключена Тогда
			Продолжить;
		КонецЕсли;
		Команда = Команды.Добавить();
		ЗаполнитьЗначенияСвойств(Команда, КомандаПечати, , "Обработчик");
		Команда.Вид = "Печать";
		Команда.Подменю = КомандаПечати.МестоРазмещения;
		Команда.МножественныйВыбор = Истина;
		Если КомандаПечати.ТипыОбъектовПечати.Количество() > 0 Тогда
			Команда.ТипПараметра = Новый ОписаниеТипов(КомандаПечати.ТипыОбъектовПечати);
		КонецЕсли;
		Команда.ВидимостьВФормах = КомандаПечати.СписокФорм;
		Если КомандаПечати.НеВыполнятьЗаписьВФорме Тогда
			Команда.РежимЗаписи = "НеЗаписывать";
		ИначеЕсли КомандаПечати.ПроверкаПроведенияПередПечатью Тогда
			Команда.РежимЗаписи = "Проводить";
		Иначе
			Команда.РежимЗаписи = "Записывать";
		КонецЕсли;
		Команда.ТребуетсяРаботаСФайлами = КомандаПечати.ТребуетсяРасширениеРаботыСФайлами;
		
		Команда.Обработчик = "УправлениеПечатьюСлужебныйКлиент.ОбработчикКоманды";
		Команда.ДополнительныеПараметры = Новый Структура(КлючиПараметровОбработчика);
		ЗаполнитьЗначенияСвойств(Команда.ДополнительныеПараметры, КомандаПечати);
	КонецЦикла;
	
КонецПроцедуры

// См. ПользователиПереопределяемый.ПриОпределенииНазначенияРолей
Процедура ПриОпределенииНазначенияРолей(НазначениеРолей) Экспорт
	
	// ТолькоДляПользователейСистемы.
	НазначениеРолей.СовместноДляПользователейИВнешнихПользователей.Добавить(
		Метаданные.Роли.РедактированиеПечатныхФорм.Имя);
	
КонецПроцедуры

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "2.4.1.1";
	Обработчик.Процедура = "УправлениеПечатью.ДобавитьРольРедактированиеПечатныхФормВПрофилиСБазовымиПравами";
	Обработчик.РежимВыполнения = "Оперативно";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.0.1.60";
	Обработчик.Процедура = "РегистрыСведений.ПользовательскиеМакетыПечати.ОбработатьПользовательскиеМакеты";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.Комментарий = НСтр("ru = 'Очищает пользовательские макеты, в которых нет изменений по сравнению с соответствующими поставляемыми макетами.
		|Отключает пользовательские макеты, которые не совместимы с текущей версией конфигурации.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("e5b0d876-c766-40a0-a0cf-ffccc83a193f");
	Обработчик.ПроцедураПроверки = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.БлокируемыеОбъекты = "РегистрСведений.ПользовательскиеМакетыПечати";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.ПользовательскиеМакетыПечати.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты = "РегистрСведений.ПользовательскиеМакетыПечати";
	Обработчик.ИзменяемыеОбъекты = "РегистрСведений.ПользовательскиеМакетыПечати";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "*";
	Обработчик.Процедура = "РегистрыСведений.ПоставляемыеМакетыПечати.ОбновитьКонтрольнуюСуммуМакетов";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.Комментарий = НСтр("ru = 'Определяет, какие поставляемые макеты печатных форм расширений изменились по отношению к предыдущей версии.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("51f71246-67e3-40e0-80e5-ebb3192fa6c0");
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность.Печать") Тогда
		МодульУправлениеПечатьюМультиязычность = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатьюМультиязычность");
		МодульУправлениеПечатьюМультиязычность.ПриДобавленииОбработчиковОбновления(Обработчики);
	КонецЕсли;
	
	Справочники.МакетыПечатныхФорм.ПриДобавленииОбработчиковОбновления(Обработчики);
	
КонецПроцедуры

// См. РаботаВБезопасномРежимеПереопределяемый.ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам.
Процедура ПриЗаполненииРазрешенийНаДоступКВнешнимРесурсам(ЗапросыРазрешений) Экспорт
	
	МодульРаботаВБезопасномРежиме = ОбщегоНазначения.ОбщийМодуль("РаботаВБезопасномРежиме");
	
	Разрешения = Новый Массив;
	Разрешения.Добавить(МодульРаботаВБезопасномРежиме.РазрешениеНаИспользованиеВнешнейКомпоненты(
		"ОбщийМакет.КомпонентаПечатиQRКода", НСтр("ru = 'Печать QR кодов.'")));
	ЗапросыРазрешений.Добавить(
		МодульРаботаВБезопасномРежиме.ЗапросНаИспользованиеВнешнихРесурсов(Разрешения));
	
КонецПроцедуры

// Параметры:
//   ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	Если Не ПравоДоступа("Редактирование", Метаданные.РегистрыСведений.ПользовательскиеМакетыПечати)
		Или МодульТекущиеДелаСервер.ДелоОтключено("МакетыПечатныхФорм") Тогда
		Возврат;
	КонецЕсли;
	
	// Если нет раздела администрирование, дело не добавляется.
	Подсистема = Метаданные.Подсистемы.Найти("Администрирование");
	Если Подсистема = Неопределено
		Или Не ПравоДоступа("Просмотр", Подсистема)
		Или Не ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(Подсистема) Тогда
		Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта("РегистрСведений.ПользовательскиеМакетыПечати");
	Иначе
		Разделы = Новый Массив;
		Разделы.Добавить(Подсистема);
	КонецЕсли;
	
	ВывестиДело = Истина;
	ПровереноНаВерсию = ХранилищеОбщихНастроек.Загрузить("ТекущиеДела", "ПечатныеФормы");
	Если ПровереноНаВерсию <> Неопределено Тогда
		ВерсияМассив  = СтрРазделить(Метаданные.Версия, ".");
		ТекущаяВерсия = ВерсияМассив[0] + ВерсияМассив[1] + ВерсияМассив[2];
		Если ПровереноНаВерсию = ТекущаяВерсия Тогда
			ВывестиДело = Ложь; // Печатные формы проверены на текущей версии.
		КонецЕсли;
	КонецЕсли;
	
	КоличествоПользовательскихМакетов = КоличествоИспользуемыхПользовательскихМакетов();
	
	Для Каждого Раздел Из Разделы Цикл
		ИдентификаторРаздела = "ПроверитьСовместимостьСТекущейВерсией" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
		
		// Добавление дела.
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор = "МакетыПечатныхФорм";
		Дело.ЕстьДела      = ВывестиДело И КоличествоПользовательскихМакетов > 0;
		Дело.Представление = НСтр("ru = 'Макеты печатных форм'");
		Дело.Количество    = КоличествоПользовательскихМакетов;
		Дело.Форма         = "РегистрСведений.ПользовательскиеМакетыПечати.Форма.ПроверкаПечатныхФорм";
		Дело.Владелец      = ИдентификаторРаздела;
		
		// Проверка наличия группы дела. Если группа отсутствует - добавляем.
		ГруппаДела = ТекущиеДела.Найти(ИдентификаторРаздела, "Идентификатор");
		Если ГруппаДела = Неопределено Тогда
			ГруппаДела = ТекущиеДела.Добавить();
			ГруппаДела.Идентификатор = ИдентификаторРаздела;
			ГруппаДела.ЕстьДела      = Дело.ЕстьДела;
			ГруппаДела.Представление = НСтр("ru = 'Проверить совместимость'");
			Если Дело.ЕстьДела Тогда
				ГруппаДела.Количество = Дело.Количество;
			КонецЕсли;
			ГруппаДела.Владелец = Раздел;
		Иначе
			Если Не ГруппаДела.ЕстьДела Тогда
				ГруппаДела.ЕстьДела = Дело.ЕстьДела;
			КонецЕсли;
			
			Если Дело.ЕстьДела Тогда
				ГруппаДела.Количество = ГруппаДела.Количество + Дело.Количество;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами.
Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт
	
	Объекты.Вставить(Метаданные.Справочники.МакетыПечатныхФорм.ПолноеИмя(), "РеквизитыРедактируемыеВГрупповойОбработке");
	
КонецПроцедуры

// Определяет, какие поставляемые макеты печатных форм конфигурации изменились по отношению к предыдущей версии.
Процедура ОбновитьКонтрольнуюСуммуМакетов() Экспорт
	
	РегистрыСведений.ОбщиеПоставляемыеМакетыПечати.ОбновитьКонтрольнуюСуммуМакетов();
	
КонецПроцедуры

Функция ПоставляемыйМакет(ПутьКМакету, КодЯзыка) Экспорт
	
	Возврат НайтиМакет(ПутьКМакету, КодЯзыка, Истина);
	
КонецФункции

Функция ОбъектМетаданныхМакета(ПутьКМакету) Экспорт
	
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ИмяМакета = ЧастиПути[ЧастиПути.ВГраница()];
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	
	ЭтоОбщийМакет = СтрРазделить(ИмяОбъекта, ".").Количество() = 1;
	
	КоллекцияМакетов = Метаданные.ОбщиеМакеты;
	Если Не ЭтоОбщийМакет Тогда
		ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта);
		Если ОбъектМетаданных = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
		КоллекцияМакетов = ОбъектМетаданных.Макеты;
	КонецЕсли;
	
	Возврат КоллекцияМакетов.Найти(ИмяМакета);
	
КонецФункции

Процедура ДобавитьЯзыкиПечатныхФорм(КодыЯзыков) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность.Печать") Тогда
		МодульУправлениеПечатьюМультиязычность = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатьюМультиязычность");
		МодульУправлениеПечатьюМультиязычность.ДобавитьЯзыкиПечатныхФорм(КодыЯзыков);
	КонецЕсли;
	
КонецПроцедуры

#Область РедактированиеТабличногоДокумента

Функция КоллекцииПолейИсточниковДанных(ИсточникиДанных) Экспорт
	
	Результат = Новый СписокЗначений;
	ОписанияОбъектов = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИсточникиДанных);
	
	ИмяИсточникаДанных = "КоллекцияДоступныхПолей";
	
	Для Каждого ОписаниеОбъекта Из ОписанияОбъектов Цикл
		ИмяОбъектаМетаданных = ОписаниеОбъекта.Значение.ПолноеИмя();
		Для Каждого СхемаКомпоновкиДанных Из СхемыКомпоновкиДанныхИсточникаПолей(ИмяОбъектаМетаданных, Ложь) Цикл
			Результат.Добавить(КонструкторФормул.КоллекцияПолей(СхемаКомпоновкиДанных.Значение), ИмяИсточникаДанных);
		КонецЦикла;
	КонецЦикла;

	Результат.Добавить(КоллекцияПолейОбщиеРеквизиты(), ИмяИсточникаДанных);
	
	Возврат Результат;
	
КонецФункции

Функция ОбщиеПоляИсточниковДанных(ИсточникиДанных) Экспорт
	
	Результат = Неопределено;
	ОписанияОбъектов = ОбщегоНазначения.ОбъектыМетаданныхПоИдентификаторам(ИсточникиДанных);

	Для Каждого ОписаниеОбъекта Из ОписанияОбъектов Цикл
		ИмяОбъектаМетаданных = ОписаниеОбъекта.Значение.ПолноеИмя();
		ПоляКоллекции = Новый Массив;
		Для Каждого СхемаКомпоновкиДанных Из СхемыКомпоновкиДанныхИсточникаПолей(ИмяОбъектаМетаданных, Ложь) Цикл
			КоллекцияПолей = КонструкторФормул.КоллекцияПолей(СхемаКомпоновкиДанных.Значение);
			Для Каждого Поле Из ПоляКоллекции(КоллекцияПолей) Цикл
				ПоляКоллекции.Добавить(Поле);
			КонецЦикла;
		КонецЦикла;
		Если Результат = Неопределено Тогда
			Результат = ПересечениеМножеств(ПоляКоллекции, ПоляКоллекции); // Свертка повторяющихся элементов.
		Иначе
			Результат = ПересечениеМножеств(Результат, ПоляКоллекции);
		КонецЕсли;
	КонецЦикла;	
	
	Если Результат = Неопределено Тогда
		Результат = Новый Массив;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура ОбновитьСписокДоступныхПолей(Форма, КоллекцииПолей, ИмяСпискаПолей) Экспорт
	
	КонструкторФормул.ОбновитьКоллекцииПолей(Форма, КоллекцииПолей, ИмяСпискаПолей);
	
КонецПроцедуры

Функция СписокОператоров(ДополнительныеПоля = Неопределено) Экспорт
	
	СписокОператоров = КонструкторФормул.СписокОператоров();
	ДобавитьГруппуОператоровФункцииДляТабличныхЧастей(СписокОператоров);
	
	Если ДополнительныеПоля <> Неопределено Тогда
		Для Каждого ГруппаДополнительногоПоля Из ДополнительныеПоля Цикл
			Группа = СписокОператоров.Строки.Найти(ГруппаДополнительногоПоля.Ключ);

			Если Группа = Неопределено Тогда
				Группа = СписокОператоров.Строки.Добавить();
				ЗаполнитьЗначенияСвойств(Группа, ГруппаДополнительногоПоля.Значение);
				Группа.Идентификатор = ГруппаДополнительногоПоля.Ключ;
			КонецЕсли;
			
			Для Каждого ДополнительноеПоле Из ГруппаДополнительногоПоля.Значение.Элементы Цикл
				Оператор = Группа.Строки.Добавить();
				ЗаполнитьЗначенияСвойств(Оператор, ДополнительноеПоле.Значение);
				Оператор.Идентификатор = ДополнительноеПоле.Ключ;
			КонецЦикла;
		КонецЦикла;
	КонецЕсли;
	
	Группа = СписокОператоров.Строки.Найти("СтроковыеФункции");
	Если Группа = Неопределено Тогда
		Группа = СписокОператоров.Строки.Добавить();
		Группа.Идентификатор = "СтроковыеФункции";
		Группа.Представление = НСтр("ru = 'Строковые функции'");
		Группа.Порядок = 5;
		Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	КонецЕсли;
	
	ДобавитьОператорВГруппу(Группа, ИмяМодуляПечати() + РазделительКоманды() + "СтрокаЛатиницей", НСтр("ru = 'Строка латиницей'"), Новый ОписаниеТипов("Строка"), Истина);
	
	Группа = СписокОператоров.Строки.Найти("ПрочиеФункции");
	Если Группа = Неопределено Тогда
		Группа = СписокОператоров.Строки.Добавить();
		Группа.Идентификатор = "ПрочиеФункции";
		Группа.Представление = НСтр("ru = 'Прочие функции'");
		Группа.Порядок = 7;
		Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	КонецЕсли;
	
	Возврат КонструкторФормул.КоллекцияПолей(СписокОператоров);
	
КонецФункции

Функция ФормулыИзТекста(Знач Текст, Знач Форма) Экспорт
	
	Результат = Новый Соответствие();
	
	Если Не ЗначениеЗаполнено(Текст) Тогда
		Возврат Результат;
	КонецЕсли;

	ПараметрыТекста = НайтиПараметрыВТексте(Текст);

	Для Каждого Параметр Из ПараметрыТекста Цикл
		Представление = Параметр;
		Если СтрЧислоВхождений(Параметр, "[") > 1 Тогда
			Представление = Сред(Параметр, 2, СтрДлина(Параметр) - 2);
		КонецЕсли;
		Формула = КонструкторФормул.ФормулаИзПредставления(Форма, Представление);
		Если Не СтрНачинаетсяС(Формула, "[") Тогда
			Формула = "[" + Формула + "]";
		КонецЕсли;
		Результат.Вставить(Параметр, Формула);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПредставленияПараметровТекста(Знач Текст, Знач Форма) Экспорт
	
	Результат = Новый Соответствие();
	
	Если Не ЗначениеЗаполнено(Текст) Тогда
		Возврат Результат;
	КонецЕсли;

	ПараметрыТекста = НайтиПараметрыВТексте(Текст);
	Для Каждого Параметр Из ПараметрыТекста Цикл
		Формула = Сред(Параметр, 2, СтрДлина(Параметр) - 2);
		Представление = КонструкторФормул.ПредставлениеФормулыПоДаннымФормы(Форма, Формула);
		Если Не СтрНачинаетсяС(Представление, "[") Или Не СтрЗаканчиваетсяНа(Представление, "]")
			Или СтрЧислоВхождений(Представление, "[") > 1 Тогда
				Представление = "[" + Представление + "]";
		КонецЕсли;
		Результат.Вставить(Параметр, Представление);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ИсточникиДанныхМакета(ПутьКМакету) Экспорт
	
	ИсточникиДанныхМакета = Справочники.МакетыПечатныхФорм.ИсточникиДанныхМакета(ПутьКМакету);
	Если ИсточникиДанныхМакета <> Неопределено Тогда
		Возврат ИсточникиДанныхМакета;
	КонецЕсли;
	
	ИсточникиДанныхМакета = Новый Массив;
	
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		Возврат ИсточникиДанныхМакета;
	КонецЕсли;
	
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	
	Если ИмяОбъекта = "ОбщийМакет" Тогда
		ИсточникиДанныхМакета.Добавить(Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка());
		Возврат ИсточникиДанныхМакета;
	КонецЕсли;
	
	ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта);
	Если ОбъектМетаданных = Неопределено Тогда
		Возврат ИсточникиДанныхМакета;
	КонецЕсли;
	
	Если Метаданные.Обработки.Содержит(ОбъектМетаданных) Тогда
		НастройкиПодключаемогоОбъекта = ПодключаемыеКоманды.НастройкиПодключаемогоОбъекта(ИмяОбъекта);
		Если ЗначениеЗаполнено(НастройкиПодключаемогоОбъекта) Тогда
			ИдентификаторыОбъектовМетаданных = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(НастройкиПодключаемогоОбъекта.Размещение, Ложь);
			Для Каждого Элемент Из ИдентификаторыОбъектовМетаданных Цикл
				ИсточникиДанныхМакета.Добавить(Элемент.Значение);
			КонецЦикла;
		КонецЕсли;
	Иначе
		ВладелецМакета = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ИмяОбъекта, Ложь);
		Если ВладелецМакета <> Неопределено Тогда
			ИсточникиДанныхМакета.Добавить(ВладелецМакета);
		КонецЕсли;
	КонецЕсли;
	
	Возврат ИсточникиДанныхМакета;
	
КонецФункции

Функция ЭтоПечатнаяФорма(Знач ИдентификаторМакета, Знач Владелец = Неопределено) Экспорт
	
	Если Не ЗначениеЗаполнено(Владелец) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ИдентификаторМакета) Тогда
		Возврат Истина;
	КонецЕсли;
	
	СсылкаМакета = Справочники.МакетыПечатныхФорм.СсылкаМакета(ИдентификаторМакета);
	Если ЗначениеЗаполнено(СсылкаМакета) Тогда
		Возврат Истина;
	КонецЕсли;
	
	ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору(Владелец);

	ИсточникиКомандПечати = ИсточникиКомандПечати();
	Если ИсточникиКомандПечати.Найти(ОбъектМетаданных) = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;

	ЧастиПути = СтрРазделить(ИдентификаторМакета, ".", Истина);
	ИдентификаторМакета = ЧастиПути[ЧастиПути.ВГраница()];
	КомандыПечати = КомандыПечатиОбъекта(ОбъектМетаданных, Ложь);
	Для Каждого КомандаПечати Из КомандыПечати Цикл
		Если КомандаПечати.МенеджерПечати = ИмяМодуляПечати() И СтрНайти(КомандаПечати.Идентификатор, ИдентификаторМакета) Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

Функция ДанныеПечати(Объекты, Поля, КодЯзыка) Экспорт
	
	ДанныеПечати = Новый Соответствие;
	ДанныеПечати["ИменаТабличныхЧастейОбъекта"] = Новый Массив;
	ДанныеПечати["НастройкиФорматаПолей"] = Новый Соответствие;
	
	Для Каждого Объект Из Объекты Цикл
		ДанныеПечати[Объект] = Новый Соответствие();
	КонецЦикла;
		
	Если Не ЗначениеЗаполнено(Поля) Тогда
		Возврат ДанныеПечати;
	КонецЕсли;
	
	ИмяОбъекта = Объекты[0].Метаданные().ПолноеИмя();
	
	СхемыКомпоновкиДанных = СхемыКомпоновкиДанныхИсточникаПолей(ИмяОбъекта, Истина);
	СпискиПолей = ОписаниеСписковПолей(СхемыКомпоновкиДанных, , ИмяОбъекта);
	
	ОписаниеПолей = Новый ТаблицаЗначений;
	ОписаниеПолей.Колонки.Добавить("Поле");
	ОписаниеПолей.Колонки.Добавить("Владелец");
	ОписаниеПолей.Колонки.Добавить("СхемаКомпоновкиДанных");
	ОписаниеПолей.Колонки.Добавить("ИдентификаторСхемыКомпоновкиДанных");
	ОписаниеПолей.Колонки.Добавить("ПутьКДанным");
	ОписаниеПолей.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число"));
	ОписаниеПолей.Колонки.Добавить("Формат");
	ОписаниеПолей.Колонки.Добавить("Тип");
	ОписаниеПолей.Колонки.Добавить("Папка", Новый ОписаниеТипов("Булево"));
	ОписаниеПолей.Колонки.Добавить("Таблица", Новый ОписаниеТипов("Булево"));
	
	ТребуемыеПоля = Новый Соответствие;

	Для Каждого ПутьКДанным Из Поля Цикл
		Пока ЗначениеЗаполнено(ПутьКДанным) Цикл
			Если ТребуемыеПоля[ПутьКДанным] = Неопределено Тогда
				ОписаниеПоля = КонструкторФормулСлужебный.ОписаниеПоля(ПутьКДанным, СпискиПолей);
				ЗаполнитьЗначенияСвойств(ОписаниеПолей.Добавить(), ОписаниеПоля);
				ТребуемыеПоля.Вставить(ПутьКДанным, ОписаниеПоля);
				
				КодЯзыкаБезРегиона = СтрРазделить(КодЯзыка, "_")[0];
				Если ЗначениеЗаполнено(КодЯзыкаБезРегиона) И Не СтрЗаканчиваетсяНа(ПутьКДанным, "." + КодЯзыкаБезРегиона)
					И ОписаниеПоля.Тип <> Неопределено И ОписаниеПоля.Тип.СодержитТип(Тип("Строка")) Тогда
					ОписаниеПоля = КонструкторФормулСлужебный.ОписаниеПоля(ПутьКДанным + "." + КодЯзыкаБезРегиона, СпискиПолей);
					Если ОписаниеПоля.ПутьКДанным <> Неопределено Тогда
						ЗаполнитьЗначенияСвойств(ОписаниеПолей.Добавить(), ОписаниеПоля);
						ТребуемыеПоля.Вставить(ПутьКДанным, ОписаниеПоля);
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
			
			ЧастиПути = СтрРазделить(ПутьКДанным, ".");
			ЧастиПути.Удалить(ЧастиПути.ВГраница());
			ПутьКДанным = СтрСоединить(ЧастиПути, ".");
		КонецЦикла;
	КонецЦикла;
	
	Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл
		Если Не ЗначениеЗаполнено(ОписаниеПоля.Формат) Тогда
			ОписаниеПоля.Формат = ФорматПоУмолчанию(ОписаниеПоля.Тип);
		КонецЕсли;
		Если ЗначениеЗаполнено(ОписаниеПоля.Владелец) Тогда
			ОписаниеПоля.Уровень = СтрЧислоВхождений(ОписаниеПоля.Поле, ".") + 1;
		КонецЕсли;
	КонецЦикла;
	
	ОписаниеПолей.Сортировать("Уровень");
	ИерархияПолей = Новый Соответствие;
	
	Для Каждого ОписаниеПоля Из ОписаниеПолей Цикл
		Если ОписаниеПоля.Уровень = 0 Тогда
			Продолжить;
		КонецЕсли;
		Владелец = НайтиПолеВИерархии(ОписаниеПоля.Владелец, ИерархияПолей);
		Если Владелец = Неопределено Тогда
			ИерархияПолей.Вставить(ОписаниеПоля.Владелец, Новый Соответствие);
			Владелец = ИерархияПолей[ОписаниеПоля.Владелец];
		КонецЕсли;
		Владелец.Вставить(ОписаниеПоля.Поле, Новый Соответствие);
	КонецЦикла;                                                                                                           
	
	ЗаполнитьДанныеПечати(ДанныеПечати, ОписаниеПолей, ИерархияПолей, Объекты, КодЯзыка);	
	
	Возврат ДанныеПечати;
	
КонецФункции

Функция СсылкаМакета(ПутьКМакету) Экспорт
	
	Возврат Справочники.МакетыПечатныхФорм.СсылкаМакета(ПутьКМакету);
	
КонецФункции

Функция ИдентификаторОбласти(Область) Экспорт
	
	Возврат УправлениеПечатьюКлиентСервер.ИдентификаторОбласти(Область);
	
КонецФункции

// Сохраняет пользовательский макет печати в информационной базе.
// 
// Параметры:
//  ОписаниеМакета - см. ОписаниеМакета
// 
// Возвращаемое значение:
//  Строка
// 
Функция ЗаписатьМакет(ОписаниеМакета) Экспорт
	
	ИмяОбъектаМетаданныхМакета = ОписаниеМакета.ИмяОбъектаМетаданныхМакета;
	АдресМакетаВоВременномХранилище = ОписаниеМакета.АдресМакетаВоВременномХранилище;
	КодЯзыка = ОписаниеМакета.КодЯзыка;
	
	Если Не ЗначениеЗаполнено(ИмяОбъектаМетаданныхМакета) Или ЗначениеЗаполнено(ОписаниеМакета.Ссылка) Тогда
		Возврат Справочники.МакетыПечатныхФорм.ЗаписатьМакет(ОписаниеМакета);
	КонецЕсли;
	
	ИзмененныйМакет = ПолучитьИзВременногоХранилища(АдресМакетаВоВременномХранилище);
	
	ЧастиИмени = СтрРазделить(ИмяОбъектаМетаданныхМакета, ".");
	ИмяМакета = ЧастиИмени[ЧастиИмени.ВГраница()];
	
	ИмяВладельца = "";
	Для НомерЧасти = 0 По ЧастиИмени.ВГраница()-1 Цикл
		Если Не ПустаяСтрока(ИмяВладельца) Тогда
			ИмяВладельца = ИмяВладельца + ".";
		КонецЕсли;
		ИмяВладельца = ИмяВладельца + ЧастиИмени[НомерЧасти];
	КонецЦикла;
	
	Если ЧастиИмени.Количество() = 3 Тогда
		УстановитьОтключениеБезопасногоРежима(Истина);
		УстановитьПривилегированныйРежим(Истина);
		
		МакетИзМетаданных = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИмяВладельца).ПолучитьМакет(ИмяМакета);
		
		УстановитьПривилегированныйРежим(Ложь);
		УстановитьОтключениеБезопасногоРежима(Ложь);
	Иначе
		МакетИзМетаданных = ПолучитьОбщийМакет(ИмяМакета);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(КодЯзыка) Тогда
		ИмяМакета = ИмяМакета + "_" + КодЯзыка;
	КонецЕсли;
	
	Запись = РегистрыСведений.ПользовательскиеМакетыПечати.СоздатьМенеджерЗаписи();
	Запись.Объект = ИмяВладельца;
	Запись.ИмяМакета = ИмяМакета;
	Если МакетыРазличаются(МакетИзМетаданных, ИзмененныйМакет) Тогда
		Запись.Использование = Истина;
		Запись.Макет = Новый ХранилищеЗначения(ИзмененныйМакет, Новый СжатиеДанных(9));
		Запись.Записать();
	Иначе
		Запись.Прочитать();
		Если Запись.Выбран() Тогда
			Запись.Удалить();
		КонецЕсли;
	КонецЕсли;
	
	Возврат ИмяОбъектаМетаданныхМакета;
	
КонецФункции

Функция СформироватьТабличныйДокумент(Макет, МассивОбъектов, ОбъектыПечати, КодЯзыка) Экспорт
	
	ПоляМакета = ПоляМакета(Макет);
	
	ДанныеПечати = ДанныеПечати(МассивОбъектов, ПоляМакета, КодЯзыка);
	НастройкиФорматаПолей = ДанныеПечати["НастройкиФорматаПолей"];
	
	ПутьКДаннымРисунков = Новый Соответствие();
	Для Каждого Рисунок Из Макет.Рисунки Цикл
		Если Рисунок.ТипРисунка <> ТипРисункаТабличногоДокумента.Группа Тогда 
			ПутьКДаннымРисунков.Вставить(Рисунок.Имя, Рисунок.ПараметрРасшифровки);
		КонецЕсли;
	КонецЦикла;
	
	ОбластиМакета = ОбластиМакета(Макет, ДанныеПечати);
	ТабличныйДокумент = Новый ТабличныйДокумент;
	
	ВыведеноРисунков = ТабличныйДокумент.Рисунки.Количество();
	Для Каждого Ссылка Из МассивОбъектов Цикл

		Если ТабличныйДокумент.ВысотаТаблицы > 0 Тогда
			ТабличныйДокумент.ВывестиГоризонтальныйРазделительСтраниц();
		КонецЕсли;
		
		НомерСтрокиНачало = ТабличныйДокумент.ВысотаТаблицы + 1;
		
		Для Каждого Элемент Из ОбластиМакета.ВсеОбласти Цикл
			ИмяОбласти = Элемент.Значение;
			УсловиеВывода = Элемент.Представление;
			КоличествоПовторений = 1;

			ИмяТаблицы = ОбластиМакета.ОбластиТаблиц[ИмяОбласти];
			Если ЗначениеЗаполнено(ИмяТаблицы) Тогда
				КоличествоПовторений = ДанныеПечати[Ссылка][ИмяТаблицы].Количество();
			КонецЕсли;
			
			Для НомерСтрокиТабличнойЧасти = 1 По КоличествоПовторений Цикл
				ОбластьМакета = Макет.ПолучитьОбласть(ИмяОбласти);
			
				ИсточникДанных = Новый Соответствие;
				ОбщегоНазначенияКлиентСервер.ДополнитьСоответствие(ИсточникДанных, ДанныеПечати[Ссылка]);
				Если ЗначениеЗаполнено(ИмяТаблицы) Тогда
					ДанныеСтрокиТабличнойЧасти = ДанныеПечати[Ссылка][ИмяТаблицы][НомерСтрокиТабличнойЧасти];
					Для Каждого КлючИЗначение Из ДанныеСтрокиТабличнойЧасти Цикл
						ИсточникДанных[ИмяТаблицы + "." + КлючИЗначение.Ключ] = КлючИЗначение.Значение;
					КонецЦикла;
				КонецЕсли;
				
				Если ЗначениеЗаполнено(УсловиеВывода) Тогда
					ВыводитьОбласть = ВычислитьВыражение("[" + УсловиеВывода + "]", ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
					Если ТипЗнч(ВыводитьОбласть) <> Тип("Булево") Или Не ВыводитьОбласть Тогда
						Продолжить;
					КонецЕсли;
				КонецЕсли;
				
				ОбработанныеЯчейки = Новый Соответствие;
				Для НомерСтроки = 1 По ОбластьМакета.ВысотаТаблицы Цикл
					Для НомерСтолбца = 1 По ОбластьМакета.ШиринаТаблицы Цикл
						ОбластьЯчейки = ОбластьМакета.Область(НомерСтроки, НомерСтолбца, НомерСтроки, НомерСтолбца);
						
						ИдентификаторОбласти = ИдентификаторОбласти(ОбластьЯчейки);
						Если ОбработанныеЯчейки[ИдентификаторОбласти] <> Неопределено Тогда
							Продолжить;
						КонецЕсли;
						ОбработанныеЯчейки[ИдентификаторОбласти] = Истина;
						
						Если Не ЗначениеЗаполнено(ОбластьЯчейки.Текст) Тогда
							Продолжить;
						КонецЕсли;
						
						ОбластьЯчейки.Текст = ЗаменитьПараметрыЗначениями(ОбластьЯчейки.Текст, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
					КонецЦикла;
				КонецЦикла;
	
				ТабличныйДокумент.Вывести(ОбластьМакета);
				Для Индекс = ВыведеноРисунков По ТабличныйДокумент.Рисунки.Количество() - 1 Цикл
					Рисунок = ТабличныйДокумент.Рисунки[Индекс];
					Если Рисунок.ТипРисунка = ТипРисункаТабличногоДокумента.Группа Тогда
						Продолжить;
					КонецЕсли;
					Рисунок.ПараметрРасшифровки = ПутьКДаннымРисунков[Рисунок.Имя];
					Если Не ЗначениеЗаполнено(Рисунок.ПараметрРасшифровки) Тогда
						Продолжить;
					КонецЕсли;
					СсылкаНаКартинку = ВычислитьВыражение(Рисунок.ПараметрРасшифровки, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
					Если ТипЗнч(СсылкаНаКартинку) = Тип("Картинка") Тогда
						Рисунок.Картинка = СсылкаНаКартинку;
					Иначе
						Рисунок.Картинка = КартинкаИзФайла(СсылкаНаКартинку);
					КонецЕсли;
				КонецЦикла;
				ВыведеноРисунков = ТабличныйДокумент.Рисунки.Количество();
			КонецЦикла;
		КонецЦикла;
		
		ЗадатьОбластьПечатиДокумента(ТабличныйДокумент, НомерСтрокиНачало, ОбъектыПечати, Ссылка);
		
	КонецЦикла;
	
	ИсточникДанных = ДанныеПечати[МассивОбъектов[0]];
	
	ТабличныйДокумент.ВерхнийКолонтитул.ТекстСлева = ЗаменитьПараметрыЗначениями(Макет.ВерхнийКолонтитул.ТекстСлева, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
	ТабличныйДокумент.ВерхнийКолонтитул.ТекстВЦентре = ЗаменитьПараметрыЗначениями(Макет.ВерхнийКолонтитул.ТекстВЦентре, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
	ТабличныйДокумент.ВерхнийКолонтитул.ТекстСправа = ЗаменитьПараметрыЗначениями(Макет.ВерхнийКолонтитул.ТекстСправа, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
	
	ТабличныйДокумент.НижнийКолонтитул.ТекстСлева = ЗаменитьПараметрыЗначениями(Макет.НижнийКолонтитул.ТекстСлева, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
	ТабличныйДокумент.НижнийКолонтитул.ТекстВЦентре = ЗаменитьПараметрыЗначениями(Макет.НижнийКолонтитул.ТекстВЦентре, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
	ТабличныйДокумент.НижнийКолонтитул.ТекстСправа = ЗаменитьПараметрыЗначениями(Макет.НижнийКолонтитул.ТекстСправа, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
	
	Возврат ТабличныйДокумент
	
КонецФункции

Процедура УдалитьМакет(ПутьКМакету, КодЯзыка = Неопределено) Экспорт
	
	Ссылка = Справочники.МакетыПечатныхФорм.СсылкаМакета(ПутьКМакету);
	Если ЗначениеЗаполнено(Ссылка) Тогда
		Справочники.МакетыПечатныхФорм.УдалитьМакет(Ссылка, КодЯзыка);
		Возврат;
	КонецЕсли;
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Макет ""%1"" не существует. Операция прервана.'"), ПутьКМакету);
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	ИмяМакета = ЧастиПути[ЧастиПути.ВГраница()];
	Если ЗначениеЗаполнено(КодЯзыка) Тогда
		ИмяМакета = ИмяМакета + "_" + КодЯзыка;
	КонецЕсли;
	
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ПользовательскиеМакетыПечати.ИмяМакета КАК ИмяМакета
	|ИЗ
	|	РегистрСведений.ПользовательскиеМакетыПечати КАК ПользовательскиеМакетыПечати
	|ГДЕ
	|	ПользовательскиеМакетыПечати.Объект = &Объект
	|	И (ПользовательскиеМакетыПечати.ИмяМакета = &ИмяМакета
	|			ИЛИ ПользовательскиеМакетыПечати.ИмяМакета ПОДОБНО &ШаблонИмениМакета СПЕЦСИМВОЛ ""~"")";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.Параметры.Вставить("Объект", ИмяОбъекта);
	Запрос.Параметры.Вставить("ИмяМакета", ИмяМакета);
	Запрос.Параметры.Вставить("ШаблонИмениМакета", ОбщегоНазначения.СформироватьСтрокуДляПоискаВЗапросе(ИмяМакета) + "_%");
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПользовательскиеМакетыПечати");
	ЭлементБлокировки.УстановитьЗначение("Объект", ИмяОбъекта);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		Выборка = Запрос.Выполнить().Выбрать();
		
		НаборЗаписей = РегистрыСведений.ПользовательскиеМакетыПечати.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Объект.Установить(ИмяОбъекта);
		Пока Выборка.Следующий() Цикл
			НаборЗаписей.Отбор.ИмяМакета.Установить(Выборка.ИмяМакета);
			НаборЗаписей.Записать();
		КонецЦикла;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Функция НайтиПараметрыВТексте(Знач Текст, Параметры = Неопределено, Знач ПозицияНачала = 0, ОткрывающихСкобок = 1, ЗакрывающихСкобок = 0) Экспорт // АПК:142 - необязательные параметры используются только при вызове самой себя.
	
	Если Параметры = Неопределено Тогда
		Параметры = Новый Массив;
	КонецЕсли;
	
	Если ПозицияНачала = 0 Тогда
		ПозицияНачала = СтрНайти(Текст, "[");
		Если ПозицияНачала = 0 Тогда
			Возврат Параметры;
		КонецЕсли;
	КонецЕсли;
	
	ПозицияКонца = СтрНайти(Текст, "]", , ПозицияНачала, ОткрывающихСкобок);
	Если ПозицияКонца > 0 Тогда
		ЗакрывающихСкобок = ЗакрывающихСкобок + 1;
		Строка = Сред(Текст, ПозицияНачала, ПозицияКонца - ПозицияНачала + 1);
		ОткрывающихСкобок = СтрЧислоВхождений(Строка, "[");
		Если ОткрывающихСкобок > ЗакрывающихСкобок Тогда
			НайтиПараметрыВТексте(Текст, Параметры, ПозицияНачала, ОткрывающихСкобок, ЗакрывающихСкобок);
		Иначе
			Параметры.Добавить(Строка);
			Текст = Сред(Текст, ПозицияКонца + 1);
			НайтиПараметрыВТексте(Текст, Параметры)
		КонецЕсли;
	КонецЕсли;
	
	Возврат Параметры;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Ссылка - СправочникСсылка.МакетыПечатныхФорм
//   * АдресМакетаВоВременномХранилище - Строка
//   * ИмяОбъектаМетаданныхМакета - Строка
//   * КодЯзыка - Строка
//   * Владелец - СправочникСсылка.ИдентификаторыОбъектовМетаданных
//              - СправочникСсылка.ИдентификаторыОбъектовРасширений
//   * Наименование - Строка
//   * ТипМакета - Строка
//   * ИсточникиДанных - Строка
// 
Функция ОписаниеМакета() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Ссылка");
	Результат.Вставить("АдресМакетаВоВременномХранилище");
	Результат.Вставить("ИмяОбъектаМетаданныхМакета");
	Результат.Вставить("КодЯзыка");
	Результат.Вставить("Владелец");
	Результат.Вставить("Наименование");
	Результат.Вставить("ТипМакета");
	Результат.Вставить("ИсточникиДанных");
	
	Возврат Результат;
	
КонецФункции

Процедура УстановитьПримерыЗначений(КоллекцияПолей, ДанныеПечати, Образец) Экспорт

	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
		Возврат;
	КонецЕсли;
	
	ПримерыЗначений = ДанныеПечати[Образец];
	НастройкиФорматаПолей = ДанныеПечати["НастройкиФорматаПолей"];
	
	Для Каждого Элемент Из КоллекцияПолей.ПолучитьЭлементы() Цикл
		Если Не ЗначениеЗаполнено(Элемент.ПутьКДанным) Тогда
			Продолжить;
		КонецЕсли;

		Если Не Элемент.Папка И Не Элемент.Таблица Тогда
			Элемент.ФорматПоУмолчанию = НастройкиФорматаПолей[Элемент.ПутьКДанным];
			
			ПутьКДаннымПоля = Элемент.ПутьКДанным;
			ПутьКДаннымТабличнойЧасти = "";
			
			ЭтоПолеТабличнойЧасти = ЭтоПолеТабличнойЧасти(Элемент.ПутьКДанным, ДанныеПечати);
			Если ЭтоПолеТабличнойЧасти Тогда
				ПутьКДаннымТабличнойЧасти = ПутьКДаннымТабличнойЧасти(ПутьКДаннымПоля, ДанныеПечати);
				ПутьКДаннымПоля = ПутьКДаннымПоляВТабличнойЧасти(ПутьКДаннымПоля, ДанныеПечати);
			КонецЕсли;

			Если ЭтоПолеТабличнойЧасти Тогда
				Если ПримерыЗначений[ПутьКДаннымТабличнойЧасти] <> Неопределено И ПримерыЗначений[ПутьКДаннымТабличнойЧасти].Количество() > 0 Тогда
					Элемент.Значение = ПримерыЗначений[ПутьКДаннымТабличнойЧасти][1][ПутьКДаннымПоля];
				КонецЕсли;
			Иначе
				Элемент.Значение = ПримерыЗначений[ПутьКДаннымПоля]
			КонецЕсли;
			Элемент.Образец = Элемент.Значение;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(Элемент.Формат) Тогда
			Элемент.Образец = Формат(Элемент.Образец, Элемент.Формат);
		КонецЕсли;
	
		УстановитьПримерыЗначений(Элемент, ДанныеПечати, Образец);
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

Функция СформироватьОфисныйДокумент(Макет, МассивОбъектов, ОбъектыПечати, КодЯзыка, ПараметрыПечати) Экспорт
	
	ДеревоМакета = ИнициализироватьМакетОфисногоДокументаСКД(Макет);
	СтруктураДокумента = ДеревоМакета.СтруктураДокумента;
	
	ПоляМакета = Новый Массив;
	
	Для Каждого Элемент Из СтруктураДокумента.ПараметрыТекста Цикл
		Текст = Элемент;
		ПараметрыТекста = НайтиПараметрыВТексте(Текст);

		Для Каждого Выражение Из ПараметрыТекста Цикл
			Выражение = Сред(Выражение, 2, СтрДлина(Выражение) - 2);
			ЭлементыФормулы = КонструкторФормулСлужебный.ЭлементыФормулы(Выражение);
			Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
				ЭтоФункция = ОписаниеЭлемента.Значение;
				Если ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				
				Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
				Операнд = ОчиститьКвадратныеСкобки(Операнд);
				Если ЗначениеЗаполнено(Операнд) Тогда
					ПоляМакета.Добавить(Операнд);
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	ДанныеПечати = ДанныеПечати(МассивОбъектов, ПоляМакета, КодЯзыка);
	
		
	ИменаТабличныхЧастейОбъекта = ДанныеПечати.Получить("ИменаТабличныхЧастейОбъекта");
	
	ПодготовитьУзлыУсловныхОбластей(СтруктураДокумента.ДеревоДокумента, СтруктураДокумента.Гиперссылки);
	УправлениеПечатьюСлужебный.ПроиндексироватьУзлы(СтруктураДокумента.ДеревоДокумента);
	УправлениеПечатьюСлужебный.НайтиОбласти(СтруктураДокумента, ИменаТабличныхЧастейОбъекта);
	
	ПараметрыДляЗаполненияШапки = Новый Массив;
		Для Каждого Область Из СтруктураДокумента.Области Цикл
			Если Не ЗначениеЗаполнено(Область.Коллекция) Тогда
				ПараметрыДляДополнения = Область.Параметры;
			Иначе
				ПараметрыДляДополнения = Новый Массив;
				Для Каждого Параметр Из Область.Параметры Цикл
					ЭлементыФормулы = КонструкторФормулСлужебный.ЭлементыФормулы(Параметр);
					Для Каждого ЭлементФормулы Из ЭлементыФормулы.ВсеЭлементы Цикл
						Если СтрЧислоВхождений(ЭлементФормулы, Область.Коллекция+".") = 0 Тогда
						ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ПараметрыДляЗаполненияШапки, 
							     ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ЭлементФормулы), Истина);
						КонецЕсли;
					КонецЦикла;
				КонецЦикла;
			КонецЕсли;
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ПараметрыДляЗаполненияШапки, ПараметрыДляДополнения, Истина);
	КонецЦикла;
				
	Для Каждого Колонтитул Из СтруктураДокумента.Колонтитулы Цикл
		Для Каждого СтрокаКолонтитула Из Колонтитул.Значение.Строки Цикл
			ПараметрыКолонтитула = НайтиПараметрыВТексте(СтрокаКолонтитула.ПолныйТекст);
			ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ПараметрыДляЗаполненияШапки, ПараметрыКолонтитула, Истина);
		КонецЦикла;
		КонецЦикла;
		 
	ОфисныеДокументы = Новый Соответствие;
	Для Каждого ОбъектПечати Из МассивОбъектов Цикл
		ДеревоМакетаДляЗаполнения = КопияДереваМакета(ДеревоМакета);
		ЗначенияПараметров = ПолучитьЗначениеПараметровОбъекта(ДанныеПечати, ОбъектПечати, ДеревоМакетаДляЗаполнения, КодЯзыка, ПараметрыПечати, ПараметрыДляЗаполненияШапки);
		ДеревоДокумента = ДеревоМакетаДляЗаполнения.СтруктураДокумента.ДеревоДокумента; 
		ДанныеОбъекта = ДанныеПечати[ОбъектПечати];
		НастройкиФорматаПолей = ДанныеПечати["НастройкиФорматаПолей"];
		ЗаполнитьКолонтитулы = Истина;
		
		Для ИндексОбласти = 0 По СтруктураДокумента.Области.Количество()-1 Цикл
			ТекущаяОбласть = СтруктураДокумента.Области[ИндексОбласти];
			Если ЗначениеЗаполнено(ТекущаяОбласть.УсловиеОбласти) Тогда
				УстановленБезопасныйРежим = БезопасныйРежим();
				УстановитьБезопасныйРежим(Истина);
				ВыводитьОбласть = ВычислитьВыражение(ТекущаяОбласть.УсловиеОбласти, ДанныеОбъекта, НастройкиФорматаПолей, КодЯзыка, Ложь);
				
				Если Не УстановленБезопасныйРежим Тогда
					УстановитьБезопасныйРежим(Ложь);
				КонецЕсли;
				
				Если ТипЗнч(ВыводитьОбласть) <> Тип("Булево") Или Не ВыводитьОбласть Тогда
					Продолжить;
				КонецЕсли;
			КонецЕсли;
			
			СтруктураОбласти = Новый Структура("ДеревоОбласти,Параметры");
			ЗаполнитьЗначенияСвойств(СтруктураОбласти, ТекущаяОбласть);
			Если ЗначениеЗаполнено(ТекущаяОбласть.Коллекция) Тогда
				МассивКоллекции = ПолучитьДанныеОбласти(ДанныеПечати, ОбъектПечати, ТекущаяОбласть, ДеревоМакетаДляЗаполнения, КодЯзыка, ПараметрыПечати);
				Для Каждого ЭлементКоллекции Из МассивКоллекции Цикл
					СтруктураОбластиСтроки = ОбщегоНазначения.СкопироватьРекурсивно(СтруктураОбласти);
					ПараметрыЗаполненияОбласти = ПараметрыЗаполненияОбласти();
					ПараметрыЗаполненияОбласти.СобратьСтроки = Ложь;
					ПараметрыЗаполненияОбласти.СтруктураОбласти = СтруктураОбластиСтроки;
					ПараметрыЗаполненияОбласти.ЗаполнятьКолонтитулы = Ложь;
					УстановитьПараметры(ДеревоМакетаДляЗаполнения, ЭлементКоллекции, ПараметрыЗаполненияОбласти);
					ДеревоМакетаДляЗаполнения.ОбластиДляВывода.Добавить(СтруктураОбластиСтроки.ДеревоОбласти);
				КонецЦикла;  
			Иначе
				СтруктураОбластиСтроки = ОбщегоНазначения.СкопироватьРекурсивно(СтруктураОбласти);
				ПараметрыЗаполненияОбласти = ПараметрыЗаполненияОбласти();
				ПараметрыЗаполненияОбласти.СобратьСтроки = Ложь;
				ПараметрыЗаполненияОбласти.СтруктураОбласти = СтруктураОбластиСтроки;
				ПараметрыЗаполненияОбласти.ЗаполнятьКолонтитулы = ЗаполнитьКолонтитулы;
				ЗаполнитьКолонтитулы = Ложь;
				УстановитьПараметры(ДеревоМакетаДляЗаполнения, ЗначенияПараметров, ПараметрыЗаполненияОбласти);
				ДеревоМакетаДляЗаполнения.ОбластиДляВывода.Добавить(СтруктураОбластиСтроки.ДеревоОбласти);
			КонецЕсли;
		КонецЦикла;
		
		УказателиНаОбласти = Новый Соответствие;
		Для ИндексОбласти = 0 По ДеревоМакетаДляЗаполнения.ОбластиДляВывода.ВГраница() Цикл
			ОбластьДляВывода = ДеревоМакетаДляЗаполнения.ОбластиДляВывода[ИндексОбласти];
			Если ОбластьДляВывода.Строки[0].Индекс = 0 Тогда 
				ДеревоДляВывода = ОбластьДляВывода;
				УказателиНаОбласти.Вставить(ОбластьДляВывода.Строки[0].Индекс, ОбластьДляВывода);
			Иначе
				ПоследнееДобавление = УказателиНаОбласти[ОбластьДляВывода.Строки[0].Индекс];
				Если ПоследнееДобавление <> Неопределено Тогда
					РодительДобавления = ?(ПоследнееДобавление.Родитель = Неопределено, ДеревоДляВывода, ПоследнееДобавление.Родитель);
					ИндексДобавления = РодительДобавления.Строки.Индекс(ПоследнееДобавление) + ОбластьДляВывода.Строки.Количество(); 
				Иначе
					СтрокаДобавления = ДеревоДокумента.Строки.Найти(ОбластьДляВывода.Строки[0].Индекс, "Индекс", Истина);
					РодительДобавления = ДеревоДляВывода.Строки.Найти(СтрокаДобавления.Родитель.Индекс, "Индекс", Истина);
					Если РодительДобавления <> Неопределено Тогда
						ИндексДобавления = РодительДобавления.Строки.Количество();
					Иначе
						РодительДобавления = ПолучитьПропущенногоРодителя(СтрокаДобавления, ДеревоДляВывода);
						ИндексДобавления = 0;
					КонецЕсли;
					
				КонецЕсли;                                     
				
				Для Каждого УзелДобавления Из ОбластьДляВывода.Строки Цикл
					НовыйУзел = УправлениеПечатьюСлужебный.СкопироватьУзел(РодительДобавления, ИндексДобавления, УзелДобавления);
					УказателиНаОбласти.Вставить(НовыйУзел.Индекс, НовыйУзел);
					УправлениеПечатьюСлужебный.СоздатьПоследующие(НовыйУзел, УзелДобавления);
					ИндексДобавления = ИндексДобавления + 1;
				КонецЦикла;
			КонецЕсли;
		КонецЦикла; 
		
		ДеревоМакетаДляЗаполнения.СтруктураДокумента.ДеревоДокумента = ДеревоДляВывода;
		
		АдресХранилищаПечатнойФормы = УправлениеПечатьюСлужебный.ПолучитьПечатнуюФорму(ДеревоМакетаДляЗаполнения);
		ОфисныеДокументы.Вставить(АдресХранилищаПечатнойФормы, ОбъектПечати);

	КонецЦикла;
	
	Возврат ОфисныеДокументы;
	
КонецФункции

Функция ПолучитьПечатнуюФорму(ДеревоМакета, АдресХранилища = Неопределено) Экспорт
	
	Возврат УправлениеПечатьюСлужебный.ПолучитьПечатнуюФорму(ДеревоМакета, АдресХранилища);
	
КонецФункции

Функция ИмяТегаУсловие() Экспорт

	Возврат УправлениеПечатьюКлиентСервер.ИмяТегаУсловие();

КонецФункции

Функция ПолучитьУзлыТекстов(УзелДокумента, СоответствиеУзлов = Неопределено) Экспорт
	
	Возврат УправлениеПечатьюСлужебный.ПолучитьУзлыТекстов(УзелДокумента, СоответствиеУзлов);
	
КонецФункции

Функция ПолучитьКлючЗаписиМакета(ИдентификаторМакета) Экспорт
	Возврат РегистрыСведений.ПользовательскиеМакетыПечати.ПолучитьКлючЗаписиМакета(ИдентификаторМакета);
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Добавляет роль РедактированиеПечатныхФорм во все профили, в которые входит роль БазовыеПраваБСП.
Процедура ДобавитьРольРедактированиеПечатныхФормВПрофилиСБазовымиПравами() Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		Возврат;
	КонецЕсли;
	
	МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
	
	НовыеРоли = Новый Массив;
	НовыеРоли.Добавить(Метаданные.Роли.БазовыеПраваБСП.Имя);
	НовыеРоли.Добавить(Метаданные.Роли.РедактированиеПечатныхФорм.Имя);
	
	ЗаменяемыеРоли = Новый Соответствие;
	ЗаменяемыеРоли.Вставить(Метаданные.Роли.БазовыеПраваБСП.Имя, НовыеРоли);
	
	МодульУправлениеДоступом.ЗаменитьРолиВПрофилях(ЗаменяемыеРоли);
	
КонецПроцедуры

// Возвращает ссылку на объект-источник внешней печатной формы.
//
// Параметры:
//  Идентификатор              - Строка - идентификатор формы;
//  ПолноеИмяОбъектаМетаданных - Строка - полное имя объекта метаданных, для которого требуется получить ссылку
//                                        на источник внешней печатной формы.
//
// Возвращаемое значение:
//  ЛюбаяСсылка
//
Функция СсылкаДополнительнойПечатнойФормы(Идентификатор, ПолноеИмяОбъектаМетаданных)
	ВнешняяПечатнаяФормаСсылка = Неопределено;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
		МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
		МодульДополнительныеОтчетыИОбработки.ПриПолученииВнешнейПечатнойФормы(Идентификатор, ПолноеИмяОбъектаМетаданных, ВнешняяПечатнаяФормаСсылка);
	КонецЕсли;
	
	Возврат ВнешняяПечатнаяФормаСсылка;
КонецФункции

// Сформировать печатные формы.
Функция СформироватьПечатныеФормы(Знач ИмяМенеджераПечати, Знач ИменаМакетов, Знач МассивОбъектов, Знач ПараметрыПечати, 
	ДопустимыеТипыОбъектовПечати = Неопределено, Знач КодЯзыка = Неопределено) Экспорт
	
	КоллекцияПечатныхФорм = ПодготовитьКоллекциюПечатныхФорм(Новый Массив);
	ОбъектыПечати = Новый СписокЗначений;
	
	ПараметрыВывода = ПодготовитьСтруктуруПараметровВывода();
	Если ЗначениеЗаполнено(КодЯзыка) Тогда
		ПараметрыВывода.КодЯзыка = КодЯзыка;
	КонецЕсли;
	
	Если ТипЗнч(ИменаМакетов) = Тип("Строка") Тогда
		ИменаМакетов = СтрРазделить(ИменаМакетов, ",");
	Иначе // Тип("Массив")
		ИменаМакетов = ОбщегоНазначения.СкопироватьРекурсивно(ИменаМакетов);
	КонецЕсли;
	
	ОбщийМенеджерПечати = ИмяМодуляПечати();
	ПрефиксВнешнихПечатныхФорм = "ВнешняяПечатнаяФорма.";
	
	ИсточникВнешнихПечатныхФорм = ИмяМенеджераПечати;
	Если ОбщегоНазначения.ЭтоСсылка(ТипЗнч(МассивОбъектов)) Тогда
		ИсточникВнешнихПечатныхФорм = МассивОбъектов.Метаданные().ПолноеИмя();
	Иначе
		Если МассивОбъектов.Количество() > 0 Тогда
			ИсточникВнешнихПечатныхФорм = МассивОбъектов[0].Метаданные().ПолноеИмя();
		КонецЕсли;
	КонецЕсли;
	ВнешниеПечатныеФормы = СписокПечатныхФормИзВнешнихИсточников(ИсточникВнешнихПечатныхФорм);
	
	// Добавление внешних печатных форм в комплект.
	ДобавленныеВнешниеПечатныеФормы = Новый Массив;
	Если ТипЗнч(ПараметрыПечати) = Тип("Структура") 
		И ПараметрыПечати.Свойство("ДополнитьКомплектВнешнимиПечатнымиФормами") 
		И ПараметрыПечати.ДополнитьКомплектВнешнимиПечатнымиФормами Тогда 
		
		ИдентификаторыВнешнихПечатныхФорм = ВнешниеПечатныеФормы.ВыгрузитьЗначения();
		Для Каждого Идентификатор Из ИдентификаторыВнешнихПечатныхФорм Цикл
			ИменаМакетов.Добавить(ПрефиксВнешнихПечатныхФорм + Идентификатор);
			ДобавленныеВнешниеПечатныеФормы.Добавить(ПрефиксВнешнихПечатныхФорм + Идентификатор);
		КонецЦикла;
	КонецЕсли;
	
	Для Каждого ИмяМакета Из ИменаМакетов Цикл
		// Проверка наличия уже напечатанной формы.
		НайденнаяПечатнаяФорма = КоллекцияПечатныхФорм.Найти(ИмяМакета, "ИмяМакета");
		Если НайденнаяПечатнаяФорма <> Неопределено Тогда
			ПоследняяДобавленнаяПечатнаяФорма = КоллекцияПечатныхФорм[КоллекцияПечатныхФорм.Количество() - 1];
			Если ПоследняяДобавленнаяПечатнаяФорма.ИмяМакета = НайденнаяПечатнаяФорма.ИмяМакета Тогда
				ПоследняяДобавленнаяПечатнаяФорма.Экземпляров = ПоследняяДобавленнаяПечатнаяФорма.Экземпляров + 1;
			Иначе
				КопияПечатнойФормы = КоллекцияПечатныхФорм.Добавить();
				ЗаполнитьЗначенияСвойств(КопияПечатнойФормы, НайденнаяПечатнаяФорма);
				КопияПечатнойФормы.Экземпляров = 1;
			КонецЕсли;
			Продолжить;
		КонецЕсли;
		
		// Поиск указания дополнительного менеджера печати в имени печатной формы.
		ИмяДополнительногоМенеджераПечати = "";
		Идентификатор = ИмяМакета;
		ВнешняяПечатнаяФорма = Неопределено;
		Если СтрНайти(Идентификатор, ПрефиксВнешнихПечатныхФорм) > 0 Тогда // это внешняя печатная форма
			Идентификатор = Сред(Идентификатор, СтрДлина(ПрефиксВнешнихПечатныхФорм) + 1);
			ВнешняяПечатнаяФорма = ВнешниеПечатныеФормы.НайтиПоЗначению(Идентификатор);
		ИначеЕсли СтрНайти(Идентификатор, ".") > 0 Тогда // Указан дополнительный менеджер печати.
			Если СтрНачинаетсяС(Идентификатор, ОбщийМенеджерПечати + ".") Тогда
				Идентификатор = Сред(Идентификатор, СтрДлина(ОбщийМенеджерПечати) + 2);
				ИмяДополнительногоМенеджераПечати = ОбщийМенеджерПечати;
			ИначеЕсли ИмяМенеджераПечати <> ОбщийМенеджерПечати Тогда
				Позиция = СтрНайти(Идентификатор, ".", НаправлениеПоиска.СКонца);
				ИмяДополнительногоМенеджераПечати = Лев(Идентификатор, Позиция - 1);
				Идентификатор = Сред(Идентификатор, Позиция + 1);
			КонецЕсли;
		КонецЕсли;
		
		// Определение внутреннего менеджера печати.
		ИспользуемыйМенеджерПечати = ИмяДополнительногоМенеджераПечати;
		Если ПустаяСтрока(ИспользуемыйМенеджерПечати) Тогда
			ИспользуемыйМенеджерПечати = ИмяМенеджераПечати;
		КонецЕсли;
		
		// Проверка соответствия печатаемых объектов выбранной печатной форме.
		ОбъектыСоответствующиеПечатнойФорме = МассивОбъектов;
		Если ДопустимыеТипыОбъектовПечати <> Неопределено И ДопустимыеТипыОбъектовПечати.Количество() > 0 Тогда
			Если ТипЗнч(МассивОбъектов) = Тип("Массив") Тогда
				ОбъектыСоответствующиеПечатнойФорме = Новый Массив;
				Для Каждого Объект Из МассивОбъектов Цикл
					Если ДопустимыеТипыОбъектовПечати.Найти(ТипЗнч(Объект)) = Неопределено Тогда
						СообщитьПечатнаяФормаНедоступна(Объект);
					Иначе
						ОбъектыСоответствующиеПечатнойФорме.Добавить(Объект);
					КонецЕсли;
				КонецЦикла;
				Если ОбъектыСоответствующиеПечатнойФорме.Количество() = 0 Тогда
					ОбъектыСоответствующиеПечатнойФорме = Неопределено;
				КонецЕсли;
			ИначеЕсли ОбщегоНазначения.ЗначениеСсылочногоТипа(МассивОбъектов) Тогда // передан не массив
				Если ДопустимыеТипыОбъектовПечати.Найти(ТипЗнч(МассивОбъектов)) = Неопределено Тогда
					СообщитьПечатнаяФормаНедоступна(МассивОбъектов);
					ОбъектыСоответствующиеПечатнойФорме = Неопределено;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		УправлениеПечатьюПереопределяемый.ПередПечатью(Идентификатор, ОбъектыСоответствующиеПечатнойФорме, ПараметрыПечати);
		
		ВременнаяКоллекцияДляОднойПечатнойФормы = ПодготовитьКоллекциюПечатныхФорм(Идентификатор);
		
		// Вызов процедуры Печать из менеджера печати.
		Если ВнешняяПечатнаяФорма <> Неопределено Тогда
			// Менеджер печати во внешней печатной форме.
			ПечатьПоВнешнемуИсточнику(
				СсылкаДополнительнойПечатнойФормы(ВнешняяПечатнаяФорма.Значение, ИсточникВнешнихПечатныхФорм),
				Новый Структура("ИдентификаторКоманды, ОбъектыНазначения", ВнешняяПечатнаяФорма.Значение, ОбъектыСоответствующиеПечатнойФорме),
				ВременнаяКоллекцияДляОднойПечатнойФормы,
				ОбъектыПечати,
				ПараметрыВывода);
		Иначе
			Если Не ПустаяСтрока(ИспользуемыйМенеджерПечати) Тогда
				// Печать внутренней печатной формы.
				Если ОбъектыСоответствующиеПечатнойФорме <> Неопределено Тогда
					ЭтоПечатнаяФормаСКД = ИспользуемыйМенеджерПечати = ИмяМодуляПечати();
					Если ЭтоПечатнаяФормаСКД Тогда
						// @skip-check query-in-loop - Малый цикл
						Печать(ОбъектыСоответствующиеПечатнойФорме, ПараметрыПечати, ВременнаяКоллекцияДляОднойПечатнойФормы, 
							ОбъектыПечати, ПараметрыВывода); 
					Иначе
						ОчиститьПоследнийИспользованныйМакет();
						МенеджерПечати = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИспользуемыйМенеджерПечати);
						Попытка
							МенеджерПечати.Печать(ОбъектыСоответствующиеПечатнойФорме, ПараметрыПечати, ВременнаяКоллекцияДляОднойПечатнойФормы, 
								ОбъектыПечати, ПараметрыВывода);
						Исключение
							Если ВременнаяКоллекцияДляОднойПечатнойФормы.Количество() <> 1 Тогда
								ВызватьИсключение;
							КонецЕсли;
							
							ЗаписьЖурналаРегистрации(НСтр("ru = 'Печать'", ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Ошибка, , ,
								ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
							
							Если Не ПравоДоступа("Изменение", Метаданные.РегистрыСведений.ПользовательскиеМакетыПечати) Тогда
								ВызватьИсключение НСтр("ru = 'Не удалось сформировать печатную форму.
									|Обратитесь к администратору.'");
							КонецЕсли;
							
							ВременнаяКоллекцияДляОднойПечатнойФормы[0].ТабличныйДокумент = Новый ТабличныйДокумент;
							ВременнаяКоллекцияДляОднойПечатнойФормы[0].ТекстОшибкиФормирования = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
							
							Если Не ЗначениеЗаполнено(ВременнаяКоллекцияДляОднойПечатнойФормы[0].ПолныйПутьКМакету) Тогда
								ВременнаяКоллекцияДляОднойПечатнойФормы[0].ПолныйПутьКМакету = ПоследнийИспользованныйМакет();
							КонецЕсли;
						КонецПопытки;
					КонецЕсли;
				Иначе
					ВременнаяКоллекцияДляОднойПечатнойФормы[0].ТабличныйДокумент = Новый ТабличныйДокумент;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
		// Проверка корректности заполнения коллекции печатных форм, полученной из менеджера печати.
		Для Каждого ОписаниеПечатнойФормы Из ВременнаяКоллекцияДляОднойПечатнойФормы Цикл
			ОбщегоНазначенияКлиентСервер.Проверить(
				ТипЗнч(ОписаниеПечатнойФормы.Экземпляров) = Тип("Число") И ОписаниеПечатнойФормы.Экземпляров > 0,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не задано количество экземпляров для печатной формы ""%1"".'"),
				?(ПустаяСтрока(ОписаниеПечатнойФормы.СинонимМакета), ОписаниеПечатнойФормы.ИмяМакета, ОписаниеПечатнойФормы.СинонимМакета)));
		КонецЦикла;
				
		// обновление коллекции
		Отказ = ВременнаяКоллекцияДляОднойПечатнойФормы.Количество() = 0;
		// Предполагается одна печатная форма, но для обратной совместимости принимается вся коллекция.
		Для Каждого ВременнаяПечатнаяФорма Из ВременнаяКоллекцияДляОднойПечатнойФормы Цикл 
			
			Если НЕ ВременнаяПечатнаяФорма.ОфисныеДокументы = Неопределено Тогда
				ВременнаяПечатнаяФорма.ТабличныйДокумент = Новый ТабличныйДокумент;
			КонецЕсли;
			
			Если Не МакетСуществует(ВременнаяПечатнаяФорма.ПолныйПутьКМакету) Тогда
				ВременнаяПечатнаяФорма.ПолныйПутьКМакету = "";
			КонецЕсли;
			
			Если ВременнаяПечатнаяФорма.ТабличныйДокумент <> Неопределено Тогда
				ПечатнаяФорма = КоллекцияПечатныхФорм.Добавить();
				ЗаполнитьЗначенияСвойств(ПечатнаяФорма, ВременнаяПечатнаяФорма);
				Если ВременнаяКоллекцияДляОднойПечатнойФормы.Количество() = 1 Тогда
					ПечатнаяФорма.ИмяМакета = ИмяМакета;
					ПечатнаяФорма.ИмяВРЕГ = ВРег(ИмяМакета);
				КонецЕсли;
				ПечатнаяФорма.Защита = ВременнаяПечатнаяФорма.ТабличныйДокумент.Защита;
			Иначе
				// Возникла ошибка при формировании печатной формы.
				Отказ = Истина;
			КонецЕсли;
			
		КонецЦикла;
		
		// Вызов исключения при возникновении ошибки.
		Если Отказ Тогда
			ТекстСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
				"ru = 'Не удалось сформировать печатную форму ""%1"". Обратитесь к администратору.'"), ИмяМакета);
			ВызватьИсключение ТекстСообщенияОбОшибке;
		КонецЕсли;
		
	КонецЦикла;
	
	ИнтеграцияПодсистемБСП.ПриПечати(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода);
	УправлениеПечатьюПереопределяемый.ПриПечати(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода);
	
	// Установка количества экземпляров табличным документам, проверка областей.
	Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
		ПроверитьРазметкуТабличногоДокументаПоОбъектамПечати(ПечатнаяФорма.ТабличныйДокумент, 
			ОбъектыПечати, ИмяМенеджераПечати, ПечатнаяФорма.ИмяМакета);
		Если ДобавленныеВнешниеПечатныеФормы.Найти(ПечатнаяФорма.ИмяМакета) <> Неопределено Тогда
			ПечатнаяФорма.Экземпляров = 0; // Для автоматически добавленных форм.
		КонецЕсли;
		Если ПечатнаяФорма.ТабличныйДокумент <> Неопределено Тогда
			ПечатнаяФорма.ТабличныйДокумент.КоличествоЭкземпляров = ПечатнаяФорма.Экземпляров;
			УбратьПодписьИПечать(ПечатнаяФорма.ТабличныйДокумент);
		КонецЕсли;
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("КоллекцияПечатныхФорм", КоллекцияПечатныхФорм);
	Результат.Вставить("ОбъектыПечати", ОбъектыПечати);
	Результат.Вставить("ПараметрыВывода", ПараметрыВывода);
	Возврат Результат;
	
КонецФункции

// Сформировать печатные формы для непосредственного вывода на принтер.
//
Функция СформироватьПечатныеФормыДляБыстройПечати(ИмяМенеджераПечати, ИменаМакетов, МассивОбъектов, ПараметрыПечати) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ТабличныеДокументы");
	Результат.Вставить("ОбъектыПечати");
	Результат.Вставить("ПараметрыВывода");
	Результат.Вставить("Отказ", Ложь);
		
	Если НЕ ПравоДоступа("Вывод", Метаданные) Тогда
		Результат.Отказ = Истина;
		Возврат Результат;
	КонецЕсли;
	
	ПечатныеФормы = СформироватьПечатныеФормы(ИмяМенеджераПечати, ИменаМакетов, МассивОбъектов, ПараметрыПечати);
		
	ТабличныеДокументы = Новый СписокЗначений;
	Для Каждого ПечатнаяФорма Из ПечатныеФормы.КоллекцияПечатныхФорм Цикл
		Если (ТипЗнч(ПечатнаяФорма.ТабличныйДокумент) = Тип("ТабличныйДокумент")) И (ПечатнаяФорма.ТабличныйДокумент.ВысотаТаблицы <> 0) Тогда
			ТабличныеДокументы.Добавить(ПечатнаяФорма.ТабличныйДокумент, ПечатнаяФорма.СинонимМакета);
		КонецЕсли;
	КонецЦикла;
	
	Результат.ТабличныеДокументы = ТабличныеДокументы;
	Результат.ОбъектыПечати      = ПечатныеФормы.ОбъектыПечати;
	Результат.ПараметрыВывода    = ПечатныеФормы.ПараметрыВывода;
	Возврат Результат;
	
КонецФункции

// Сформировать печатные формы для непосредственного вывода на принтер
// в серверном режиме в обычном приложении.
//
Функция СформироватьПечатныеФормыДляБыстройПечатиОбычноеПриложение(ИмяМенеджераПечати, ИменаМакетов, МассивОбъектов, ПараметрыПечати) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Адрес");
	Результат.Вставить("ОбъектыПечати");
	Результат.Вставить("ПараметрыВывода");
	Результат.Вставить("Отказ", Ложь);
	
	ПечатныеФормы = СформироватьПечатныеФормыДляБыстройПечати(ИмяМенеджераПечати, ИменаМакетов, МассивОбъектов, ПараметрыПечати);
	
	Если ПечатныеФормы.Отказ Тогда
		Результат.Отказ = ПечатныеФормы.Отказ;
		Возврат Результат;
	КонецЕсли;
	
	Результат.ОбъектыПечати = Новый Соответствие;
	
	Для Каждого ОбъектПечати Из ПечатныеФормы.ОбъектыПечати Цикл
		Результат.ОбъектыПечати.Вставить(ОбъектПечати.Представление, ОбъектПечати.Значение);
	КонецЦикла;
	
	Результат.Адрес = ПоместитьВоВременноеХранилище(ПечатныеФормы.ТабличныеДокументы);
	Возврат Результат;
	
КонецФункции

// Фильтрует список команд печати в соответствии с установленными функциональными опциями.
Процедура ОпределитьВидимостьКомандПечатиПоФункциональнымОпциям(КомандыПечати, Форма = Неопределено)
	Для каждого ОписаниеКомандыПечати Из КомандыПечати Цикл
		ФункциональныеОпцииКомандыПечати = СтрРазделить(ОписаниеКомандыПечати.ФункциональныеОпции, ", ", Ложь);
		ВидимостьКоманды = ФункциональныеОпцииКомандыПечати.Количество() = 0;
		Для Каждого ФункциональнаяОпция Из ФункциональныеОпцииКомандыПечати Цикл
			Если ТипЗнч(Форма) = Тип("ФормаКлиентскогоПриложения") Тогда
				ВидимостьКоманды = ВидимостьКоманды Или Форма.ПолучитьФункциональнуюОпциюФормы(ФункциональнаяОпция);
			Иначе
				ВидимостьКоманды = ВидимостьКоманды Или ПолучитьФункциональнуюОпцию(ФункциональнаяОпция);
			КонецЕсли;
			
			Если ВидимостьКоманды Тогда
				Прервать;
			КонецЕсли;
		КонецЦикла;
		ОписаниеКомандыПечати.СкрытаФункциональнымиОпциями = Не ВидимостьКоманды;
	КонецЦикла;
КонецПроцедуры

Функция КомпонентаФормированияQRКода()
	
	ТекстОшибки = НСтр("ru = 'Не удалось подключить внешнюю компоненту для генерации QR-кода. Подробности в журнале регистрации.'");
	
	Результат = ОбщегоНазначения.ПодключитьКомпонентуИзМакета("QRCodeExtension", "ОбщийМакет.КомпонентаПечатиQRКода");
	Если Результат = Неопределено Тогда 
		ОбщегоНазначения.СообщитьПользователю(ТекстОшибки);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура СообщитьПечатнаяФормаНедоступна(Объект)
	ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Печать %1 не выполнена: выбранная печатная форма недоступна.'"), Объект);
	ОбщегоНазначения.СообщитьПользователю(ТекстСообщения, Объект);
КонецПроцедуры

// Формирует пакет документов для отправки на принтер.
Функция ПакетДокументов(ТабличныеДокументы, ОбъектыПечати, ПечататьКомплектами, КоличествоЭкземпляров = 1) Экспорт
	
	ПакетОтображаемыхДокументов = Новый ПакетОтображаемыхДокументов;
	ПакетОтображаемыхДокументов.РазборПоКопиям = Истина;
	КоллекцияПечатныхФорм = ТабличныеДокументы.ВыгрузитьЗначения();
	
	Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
		ПечататьКомплектами = ПечататьКомплектами Или ПечатнаяФорма.ДвусторонняяПечать <> ТипДвустороннейПечати.Нет;
	КонецЦикла;
	
	Если ПечататьКомплектами И ОбъектыПечати.Количество() > 1 Тогда 
		Для Каждого ОбъектПечати Из ОбъектыПечати Цикл
			ИмяОбласти = ОбъектПечати.Представление;
			Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
				Область = ПечатнаяФорма.Области.Найти(ИмяОбласти);
				Если Область = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				ТабличныйДокумент = ПечатнаяФорма.ПолучитьОбласть(Область.Верх, , Область.Низ);
				ЗаполнитьЗначенияСвойств(ТабличныйДокумент, ПечатнаяФорма, КопируемыеСвойстваТабличногоДокумента());
				
				ПакетОтображаемыхДокументов.Состав.Добавить().Данные = ПакетСОднимТабличнымДокументом(ТабличныйДокумент);
			КонецЦикла;
		КонецЦикла;
	Иначе
		Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
			ТабличныйДокумент = Новый ТабличныйДокумент;
			ТабличныйДокумент.Вывести(ПечатнаяФорма);
			ЗаполнитьЗначенияСвойств(ТабличныйДокумент, ПечатнаяФорма, КопируемыеСвойстваТабличногоДокумента());
			ПакетОтображаемыхДокументов.Состав.Добавить().Данные = ПакетСОднимТабличнымДокументом(ТабличныйДокумент);
		КонецЦикла;
	КонецЕсли;
	
	ПакетКомплектов = Новый ПакетОтображаемыхДокументов;
	ПакетКомплектов.РазборПоКопиям = Истина;
	Для Номер = 1 По КоличествоЭкземпляров Цикл
		ПакетКомплектов.Состав.Добавить().Данные = ПакетОтображаемыхДокументов;
	КонецЦикла;
	
	Возврат ПакетКомплектов;
	
КонецФункции

// Заворачивает табличный документ в пакет отображаемых документов.
Функция ПакетСОднимТабличнымДокументом(ТабличныйДокумент)
	АдресТабличногоДокументаВоВременномХранилище = ПоместитьВоВременноеХранилище(ТабличныйДокумент);
	ПакетСОднимДокументом = Новый ПакетОтображаемыхДокументов;
	ПакетСОднимДокументом.РазборПоКопиям = Истина;
	ПакетСОднимДокументом.Состав.Добавить(АдресТабличногоДокументаВоВременномХранилище);
	ЗаполнитьЗначенияСвойств(ПакетСОднимДокументом, ТабличныйДокумент, "Вывод, ДвусторонняяПечать, ИмяПринтера, КоличествоЭкземпляров, ТочностьПечати");
	Если ТабличныйДокумент.РазборПоКопиям <> Неопределено Тогда
		ПакетСОднимДокументом.РазборПоКопиям = ТабличныйДокумент.РазборПоКопиям;
	КонецЕсли;
	Возврат ПакетСОднимДокументом;
КонецФункции

// Собирает список команд печати из нескольких объектов.
Процедура ЗаполнитьКомандыПечатиДляСпискаОбъектов(СписокОбъектов, КомандыПечати)
	ИсточникиКомандПечати = Новый Соответствие;
	Для Каждого ИсточникКомандПечати Из ИсточникиКомандПечати() Цикл
		ИсточникиКомандПечати.Вставить(ИсточникКомандПечати, Истина);
	КонецЦикла;
	
	Для Каждого ОбъектМетаданных Из СписокОбъектов Цикл
		Если ИсточникиКомандПечати[ОбъектМетаданных] = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		КомандыПечатиФормы = КомандыПечатиОбъекта(ОбъектМетаданных); // @skip-check query-in-loop - Малый цикл
		
		Для Каждого ДобавляемаяКомандаПечати Из КомандыПечатиФормы Цикл
			Если ДобавляемаяКомандаПечати.Отключена Тогда
				Продолжить;
			КонецЕсли;
			// Поиск аналогичной ранее добавленной команды печати.
			НайденныеКоманды = КомандыПечати.НайтиСтроки(Новый Структура("УникальныйИдентификатор", ДобавляемаяКомандаПечати.УникальныйИдентификатор));
			
			Для Каждого ИмеющаясяКомандаПечати Из НайденныеКоманды Цикл
				// Если уже есть такая команда, дополняем список типов объектов, для которых она предназначена.
				ТипОбъекта = Тип(СтрЗаменить(ОбъектМетаданных.ПолноеИмя(), ".", "Ссылка."));
				Если ИмеющаясяКомандаПечати.ТипыОбъектовПечати.Найти(ТипОбъекта) = Неопределено Тогда
					ИмеющаясяКомандаПечати.ТипыОбъектовПечати.Добавить(ТипОбъекта);
				КонецЕсли;
				Если ЗначениеЗаполнено(ДобавляемаяКомандаПечати.УсловияВидимости) Тогда
					ИмеющаясяКомандаПечати.УсловияВидимостиПоТипамОбъектов.Вставить(ТипОбъекта, ДобавляемаяКомандаПечати.УсловияВидимости);
				КонецЕсли;
				// Очистим МенеджерПечати в случае, если у имеющейся команды он отличается.
				Если ИмеющаясяКомандаПечати.МенеджерПечати <> ДобавляемаяКомандаПечати.МенеджерПечати Тогда
					ИмеющаясяКомандаПечати.МенеджерПечати = "";
				КонецЕсли;
			КонецЦикла;
			Если НайденныеКоманды.Количество() > 0 Тогда
				Продолжить;
			КонецЕсли;
			
			Если ДобавляемаяКомандаПечати.ТипыОбъектовПечати.Количество() = 0 Тогда
				ДобавляемаяКомандаПечати.ТипыОбъектовПечати.Добавить(Тип(СтрЗаменить(ОбъектМетаданных.ПолноеИмя(), ".", "Ссылка.")));
			КонецЕсли;
			ЗаполнитьЗначенияСвойств(КомандыПечати.Добавить(), ДобавляемаяКомандаПечати);
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

// Только для внутреннего использования.
//
Функция КоличествоИспользуемыхПользовательскихМакетов()
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ПользовательскиеМакетыПечати.ИмяМакета
	|ИЗ
	|	РегистрСведений.ПользовательскиеМакетыПечати КАК ПользовательскиеМакетыПечати
	|ГДЕ
	|	ПользовательскиеМакетыПечати.Использование = ИСТИНА";
	
	Результат = Запрос.Выполнить().Выгрузить();
	
	Возврат Результат.Количество();
	
КонецФункции

Процедура УстановитьНастройкиКомандПечати(КомандыПечати, Владелец)
	
	УстановитьПривилегированныйРежим(Истина);
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	НастройкиКомандПечати.УникальныйИдентификатор КАК УникальныйИдентификатор
	|ИЗ
	|	РегистрСведений.НастройкиКомандПечати КАК НастройкиКомандПечати
	|ГДЕ
	|	НастройкиКомандПечати.Владелец = &Владелец
	|	И НЕ НастройкиКомандПечати.Видимость";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Владелец", Владелец);
	Выборка = Запрос.Выполнить().Выбрать();
	
	СписокОтключенных = Новый Соответствие;
	Пока Выборка.Следующий() Цикл
		СписокОтключенных.Вставить(Выборка.УникальныйИдентификатор, Истина);
	КонецЦикла;     
	
	ПроверкаПроведенияПередПечатью = НастройкиПечати().ПроверкаПроведенияПередПечатью;
	
	Для Каждого КомандаПечати Из КомандыПечати Цикл
		КомандаПечати.УникальныйИдентификатор = УникальныйИдентификаторКомандыПечати(КомандаПечати);
		Если СписокОтключенных[КомандаПечати.УникальныйИдентификатор] <> Неопределено Тогда
			КомандаПечати.Отключена = Истина;
		КонецЕсли;
		КомандаПечати.ФорматСохранения = Строка(КомандаПечати.ФорматСохранения);
		
		Если КомандаПечати.ПроверкаПроведенияПередПечатью = Неопределено Тогда
			КомандаПечати.ПроверкаПроведенияПередПечатью = ПроверкаПроведенияПередПечатью;
		КонецЕсли;

	КонецЦикла;
	
КонецПроцедуры

Процедура ИсправитьПризнакПроверкаПроведенияПередПечатью(КомандыПечати, ОбъектМетаданных)
	
	Если Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда
		Если ОбъектМетаданных.Проведение = Метаданные.СвойстваОбъектов.Проведение.Запретить Тогда
			КомандыПечати.ЗаполнитьЗначения(Ложь, "ПроверкаПроведенияПередПечатью");
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры


Функция УникальныйИдентификаторКомандыПечати(КомандаПечати)
	
	Параметры = Новый Массив;
	Параметры.Добавить("Идентификатор");
	Параметры.Добавить("МенеджерПечати");
	Параметры.Добавить("Обработчик");
	Параметры.Добавить("СразуНаПринтер");
	Параметры.Добавить("ФорматСохранения");
	Параметры.Добавить("ФиксированныйКомплект");
	Параметры.Добавить("ДополнительныеПараметры");
	
	СтруктураПараметров = Новый Структура(СтрСоединить(Параметры, ","));
	ЗаполнитьЗначенияСвойств(СтруктураПараметров, КомандаПечати);
	
	Возврат ОбщегоНазначения.КонтрольнаяСуммаСтрокой(СтруктураПараметров);
	
КонецФункции

Функция КомандыПечатиОбъекта(ОбъектМетаданных, СПечатнымиФормами = Истина) Экспорт
	КомандыПечати = СоздатьКоллекциюКомандПечати();
	Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда 
		Возврат КомандыПечати;
	КонецЕсли;	
	
	Источники = ПодключаемыеКоманды.ДеревоИсточниковКоманд();
	НастройкиAPI = ПодключаемыеКоманды.НастройкиПрограммногоИнтерфейсаПодключаемыхОбъектов();
	ПодключенныеОтчетыИОбработки = ПодключаемыеКоманды.ТаблицаПодключаемыхОбъектов(НастройкиAPI);
	Источник = ПодключаемыеКоманды.ЗарегистрироватьИсточник(ОбъектМетаданных, Источники, ПодключенныеОтчетыИОбработки, НастройкиAPI);
	Если Источник.Менеджер = Неопределено Тогда
		Возврат КомандыПечати;
	КонецЕсли;
	
	ДобавляемыеКомандыПечати = СоздатьКоллекциюКомандПечати();
	Если НастройкиПечатиОбъекта(Источник.Менеджер).ПриДобавленииКомандПечати Тогда
		Источник.Менеджер.ДобавитьКомандыПечати(ДобавляемыеКомандыПечати);
	КонецЕсли;

	Если СПечатнымиФормами Тогда
		ДобавитьКомандыПечати(ДобавляемыеКомандыПечати, ОбъектМетаданных);
	КонецЕсли;
	
	Для Каждого КомандаПечати Из ДобавляемыеКомандыПечати Цикл
		Если КомандаПечати.МенеджерПечати = Неопределено Тогда
			КомандаПечати.МенеджерПечати = Источник.ПолноеИмя;
		КонецЕсли;
		Если КомандаПечати.Порядок = 0 Тогда
			КомандаПечати.Порядок = 50;
		КонецЕсли;
		ЗаполнитьЗначенияСвойств(КомандыПечати.Добавить(), КомандаПечати);
	КонецЦикла;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
		МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
		МодульДополнительныеОтчетыИОбработки.ПриПолученииКомандПечати(КомандыПечати, Источник.ПолноеИмя);
	КонецЕсли;
	
	УправлениеПечатьюПереопределяемый.ПриПолученииКомандПечати(Источник.ПолноеИмя, КомандыПечати);
	
	КомандыПечати.Индексы.Добавить("МенеджерПечати");
	Найденные = ПодключенныеОтчетыИОбработки.НайтиСтроки(Новый Структура("ДобавитьКомандыПечати", Истина));
	Для Каждого ПодключенныйОбъект Из Найденные Цикл
		ПодключенныйОбъект.Менеджер.ДобавитьКомандыПечати(КомандыПечати);
		ДобавленныеКоманды = КомандыПечати.НайтиСтроки(Новый Структура("МенеджерПечати", Неопределено));
		Для Каждого Команда Из ДобавленныеКоманды Цикл
			Команда.МенеджерПечати = ПодключенныйОбъект.ПолноеИмя;
		КонецЦикла;
	КонецЦикла;
	
	ТипОбъекта = Неопределено;
	Если ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ОбъектМетаданных) Тогда
		ТипОбъекта = Тип(СтрЗаменить(ОбъектМетаданных.ПолноеИмя(), ".", "Ссылка."));
	КонецЕсли;
	
	Для Каждого КомандаПечати Из КомандыПечати Цикл
		КомандаПечати.ДополнительныеПараметры.Вставить("ДополнитьКомплектВнешнимиПечатнымиФормами", КомандаПечати.ДополнитьКомплектВнешнимиПечатнымиФормами);
		Если ЗначениеЗаполнено(ТипОбъекта) И ЗначениеЗаполнено(КомандаПечати.УсловияВидимости) Тогда
			КомандаПечати.УсловияВидимостиПоТипамОбъектов.Вставить(ТипОбъекта, КомандаПечати.УсловияВидимости);
		КонецЕсли;
		Если КомандаПечати.ВыполнятьВФоновомЗадании = Неопределено Тогда
			КомандаПечати.ВыполнятьВФоновомЗадании = НРег(КомандаПечати.МенеджерПечати) = НРег("УправлениеПечатью")
				И Не ОбщегоНазначения.ИнформационнаяБазаФайловая();
		КонецЕсли;
	КонецЦикла;
	
	КомандыПечати.Сортировать("Порядок Возр, Представление Возр");
	ИсправитьПризнакПроверкаПроведенияПередПечатью(КомандыПечати, ОбъектМетаданных);
	УстановитьНастройкиКомандПечати(КомандыПечати, Источник.СсылкаМетаданных);
	ОпределитьВидимостьКомандПечатиПоФункциональнымОпциям(КомандыПечати);
	
	КомандыПечати.Индексы.Добавить("УникальныйИдентификатор");
	Возврат КомандыПечати;
КонецФункции


// Параметры:
//   ТабличныйДокумент - ТабличныйДокумент
//   ОбъектыПечати - СписокЗначений
//   МенеджерПечати - Строка
//   Идентификатор - Строка
//
Процедура ПроверитьРазметкуТабличногоДокументаПоОбъектамПечати(ТабличныйДокумент, ОбъектыПечати, Знач МенеджерПечати, Знач Идентификатор)
	
	Если ТабличныйДокумент.ВысотаТаблицы = 0 Или ОбъектыПечати.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ЕстьРазметкаПоОбъектамПечати = Ложь;
	Для Каждого ОбъектПечати Из ОбъектыПечати Цикл
		Для Каждого Область Из ТабличныйДокумент.Области Цикл
			Если Область.Имя = ОбъектПечати.Представление Тогда
				ЕстьРазметкаПоОбъектамПечати = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Если СтрНайти(Идентификатор, ".") > 0 Тогда
		Позиция = СтрНайти(Идентификатор, ".", НаправлениеПоиска.СКонца);
		МенеджерПечати = Лев(Идентификатор, Позиция - 1);
		Идентификатор = Сред(Идентификатор, Позиция + 1);
	КонецЕсли;
	
	ТекстОшибкиРазметки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
		"ru = 'Отсутствует разметка табличного документа ""%1"" по объектам печати.
		|Используйте процедуру %2
		|при формировании табличного документа'"), 
		Идентификатор, "УправлениеПечатью.ЗадатьОбластьПечатиДокумента");
	
	ОбщегоНазначенияКлиентСервер.Проверить(ЕстьРазметкаПоОбъектамПечати, ТекстОшибкиРазметки, МенеджерПечати + "." + "Печать()");
	
КонецПроцедуры

Функция ЧастиИмениМакета(ПолноеИмяМакета)
	ЧастиСтроки = СтрРазделить(ПолноеИмяМакета, ".");
	ИндексПоследнегоЭлемента = ЧастиСтроки.ВГраница();
	ИмяМакета = ЧастиСтроки[ИндексПоследнегоЭлемента];
	ЧастиСтроки.Удалить(ИндексПоследнегоЭлемента);
	ИмяОбъекта = СтрСоединить(ЧастиСтроки, ".");
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяМакета", ИмяМакета);
	Результат.Вставить("ИмяОбъекта", ИмяОбъекта);
	
	Возврат Результат;
КонецФункции

Функция КопируемыеСвойстваТабличногоДокумента() Экспорт
	Возврат "АвтоМасштаб,Вывод,ВысотаСтраницы,ДвусторонняяПечать,Защита,ИмяПринтера,КодЯзыка,
	|КоличествоЭкземпляров,МасштабПечати,НомерПервойСтраницы,ОриентацияСтраницы,ПолеСверху,ПолеСлева,
	|ПолеСнизу,ПолеСправа,РазборПоКопиям,РазмерКолонтитулаСверху,РазмерКолонтитулаСнизу,РазмерСтраницы,
	|ТочностьПечати,ФоноваяКартинка,ЧерноБелаяПечать,ШиринаСтраницы,ЭкземпляровНаСтранице";
КонецФункции

Функция МакетыРазличаются(Знач ИсходныйМакет, ИзмененныйМакет) Экспорт
	Возврат ОбщегоНазначения.КонтрольнаяСуммаСтрокой(НормализоватьМакет(ИсходныйМакет)) <> ОбщегоНазначения.КонтрольнаяСуммаСтрокой(НормализоватьМакет(ИзмененныйМакет));
КонецФункции

Функция НормализоватьМакет(Знач Макет)
	ХранилищеМакета = Новый ХранилищеЗначения(Макет);
	Возврат ХранилищеМакета.Получить();
КонецФункции

Функция ТекстТипОбластиУказанНекорректно()
	Возврат НСтр("ru = 'Тип области не указан или указан некорректно.'");
КонецФункции

// Параметры:
//  ОбъектыПечати - СписокЗначений
//  ТабличныйДокумент - ТабличныйДокумент
//
Функция ПодписиИПечатиОбластей(ОбъектыПечати) Экспорт
	
	ПодписиИПечати = ПодписиИПечатиОбъектов(ОбъектыПечати);
	
	ПодписиИПечатиОбластей = Новый Соответствие;
	Для Каждого ОбъектПечати Из ОбъектыПечати Цикл
		СсылкаНаОбъект = ОбъектПечати.Значение;
		КомплектПодписейИПечатей = ПодписиИПечати[СсылкаНаОбъект];
		ПодписиИПечатиОбластей.Вставить(ОбъектПечати.Представление, КомплектПодписейИПечатей);
	КонецЦикла;
	
	Возврат ПодписиИПечатиОбластей;
	
КонецФункции

Функция ПодписиИПечатиТабличногоДокумента(ОбъектыПечати, Макет, КодЯзыка) Экспорт
	
	Поля = Новый Массив;
	
	Тексты = Новый Соответствие;
	Для Каждого Рисунок Из Макет.Рисунки Цикл
		Если Рисунок.ТипРисунка <> ТипРисункаТабличногоДокумента.Группа Тогда 
			Тексты.Вставить(Рисунок.ПараметрРасшифровки, Истина);
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого Элемент Из Тексты Цикл
		Текст = Элемент.Ключ;
		ПараметрыТекста = НайтиПараметрыВТексте(Текст);
		Для Каждого Выражение Из ПараметрыТекста Цикл
			Выражение = Сред(Выражение, 2, СтрДлина(Выражение) - 2);
			ЭлементыФормулы = КонструкторФормулСлужебный.ЭлементыФормулы(Выражение);
			Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
				ЭтоФункция = ОписаниеЭлемента.Значение;
				Если ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				
				Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
				Операнд = ОчиститьКвадратныеСкобки(Операнд);
				Если ЗначениеЗаполнено(Операнд) Тогда
					Поля.Добавить(Операнд);
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	Объекты = ОбъектыПечати.ВыгрузитьЗначения();
	ДанныеПечати = ДанныеПечати(Объекты, Поля, КодЯзыка);

	Результат = Новый Соответствие;
	
	Для Каждого ОписаниеОбласти Из ОбъектыПечати Цикл
		Объект = ОписаниеОбласти.Значение;
		ИмяОбласти = ОписаниеОбласти.Представление;
	
		Картинки = Новый Соответствие;
		Для Каждого Поле Из Поля Цикл
			Если Картинки[Поле] <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			СсылкаНаКартинку = ДанныеПечати[Объект][Поле];
			Картинка = КартинкаИзФайла(СсылкаНаКартинку);
			Картинки.Вставить("[" + Поле + "]", Картинка);
		КонецЦикла;
		
		Результат.Вставить(ИмяОбласти, Картинки);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПодписиИПечатиОбъектов(Знач ОбъектыПечати) Экспорт
	
	СписокОбъектов = ОбъектыПечати.ВыгрузитьЗначения();
	ПодписиИПечати = Новый Соответствие;
	ИнтеграцияПодсистемБСП.ПриПолученииПодписейИПечатей(СписокОбъектов, ПодписиИПечати);
	УправлениеПечатьюПереопределяемый.ПриПолученииПодписейИПечатей(СписокОбъектов, ПодписиИПечати);
	
	Возврат ПодписиИПечати;
	
КонецФункции

Процедура ДобавитьПодписьИПечать(ТабличныйДокумент, ПодписиИПечатиОбластей) Экспорт
	
	Для Каждого Рисунок Из ТабличныйДокумент.Рисунки Цикл
		Позиция = СтрНайти(Рисунок.Имя, "_Документ_");
		Если Позиция > 0 Тогда
			ИмяОбластиОбъекта = Сред(Рисунок.Имя, Позиция + 1);
			
			КомплектПодписейИПечатей = ПодписиИПечатиОбластей[ИмяОбластиОбъекта];
			Если КомплектПодписейИПечатей = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Если Рисунок.ТипРисунка = ТипРисункаТабличногоДокумента.Группа Тогда 
				Продолжить;
			КонецЕсли;

			Если ЗначениеЗаполнено(Рисунок.ПараметрРасшифровки) Тогда
				Картинка = КомплектПодписейИПечатей[Рисунок.ПараметрРасшифровки];
			Иначе
				Картинка = КомплектПодписейИПечатей[Лев(Рисунок.Имя, Позиция - 1)];
			КонецЕсли;
			
			Если Картинка <> Неопределено Тогда
				Рисунок.Картинка = Картинка;
			КонецЕсли;
			Рисунок.Линия = Новый Линия(ТипЛинииРисункаТабличногоДокумента.НетЛинии);
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Процедура УбратьПодписьИПечать(ТабличныйДокумент, СкрыватьПодписиИПечати = Ложь) Экспорт
	
	УдаляемыеРисунки = Новый Массив;
	Для Каждого Рисунок Из ТабличныйДокумент.Рисунки Цикл
		Если ЭтоПодписьИлиПечать(Рисунок) Тогда
			Рисунок.Картинка = Новый Картинка;
			Рисунок.Линия = Новый Линия(ТипЛинииРисункаТабличногоДокумента.НетЛинии);
			Если СкрыватьПодписиИПечати Тогда
				УдаляемыеРисунки.Добавить(Рисунок);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого Рисунок Из УдаляемыеРисунки Цикл
		ТабличныйДокумент.Рисунки.Удалить(Рисунок);
	КонецЦикла;
	
КонецПроцедуры

Функция ЭтоПодписьИлиПечать(Рисунок) Экспорт
	
	Возврат Рисунок.ТипРисунка = ТипРисункаТабличногоДокумента.Картинка И СтрНайти(Рисунок.Имя, "_Документ_") > 0;
	
КонецФункции

Функция ПрефиксыИменОбластейСПодписьюИПечатью() Экспорт
	
	Результат = Новый Массив;
	Результат.Добавить("Печать");
	Результат.Добавить("Подпись");
	Результат.Добавить("Факсимиле");
	
	Возврат Результат;
	
КонецФункции

Функция СформироватьВнешнююПечатнуюФорму(ДополнительнаяОбработкаСсылка, Идентификатор, СписокОбъектов)
	
	ПараметрыИсточника = Новый Структура;
	ПараметрыИсточника.Вставить("ИдентификаторКоманды", Идентификатор);
	ПараметрыИсточника.Вставить("ОбъектыНазначения", СписокОбъектов);
	
	КоллекцияПечатныхФорм = Неопределено;
	ОбъектыПечати = Новый СписокЗначений;
	ПараметрыВывода = ПодготовитьСтруктуруПараметровВывода();
	
	ПечатьПоВнешнемуИсточнику(ДополнительнаяОбработкаСсылка, ПараметрыИсточника, КоллекцияПечатныхФорм,
	ОбъектыПечати, ПараметрыВывода);
	
	Результат = Новый Структура;
	Результат.Вставить("КоллекцияПечатныхФорм", КоллекцияПечатныхФорм);
	Результат.Вставить("ОбъектыПечати", ОбъектыПечати);
	Результат.Вставить("ПараметрыВывода", ПараметрыВывода);
	
	Возврат Результат;
	
КонецФункции

Процедура ВставитьКартинкиВHTML(ИмяФайлаHTML) Экспорт
	
	ТекстовыйДокумент = Новый ТекстовыйДокумент();
	ТекстовыйДокумент.Прочитать(ИмяФайлаHTML, КодировкаТекста.UTF8);
	ТекстHTML = ТекстовыйДокумент.ПолучитьТекст();
	
	ФайлHTML = Новый Файл(ИмяФайлаHTML);
	
	ИмяКаталогаКартинок = ФайлHTML.ИмяБезРасширения + "_files";
	ПутьКаталогаКартинок = СтрЗаменить(ФайлHTML.ПолноеИмя, ФайлHTML.Имя, ИмяКаталогаКартинок);
	
	// Ожидается, что в каталоге будут только картинки.
	ФайлыКартинок = НайтиФайлы(ПутьКаталогаКартинок, "*");
	
	Для Каждого ФайлКартинки Из ФайлыКартинок Цикл
		КартинкаТекстом = Base64Строка(Новый ДвоичныеДанные(ФайлКартинки.ПолноеИмя));
		КартинкаТекстом = "data:image/" + Сред(ФайлКартинки.Расширение,2) + ";base64," + Символы.ПС + КартинкаТекстом;
		
		ТекстHTML = СтрЗаменить(ТекстHTML, ИмяКаталогаКартинок + "\" + ФайлКартинки.Имя, КартинкаТекстом);
	КонецЦикла;
		
	ТекстовыйДокумент.УстановитьТекст(ТекстHTML);
	ТекстовыйДокумент.Записать(ИмяФайлаHTML, КодировкаТекста.UTF8);
	
КонецПроцедуры

Функция ИмяФайла(ПутьКФайлу)
	Файл = Новый Файл(ПутьКФайлу);
	Возврат Файл.Имя;
КонецФункции

Функция УпаковатьВАрхив(СписокФайлов)
	
	Если СписокФайлов.Количество() = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ПотокВПамяти = Новый ПотокВПамяти;
	ЗаписьZipФайла = Новый ЗаписьZipФайла(ПотокВПамяти);
	
	ИмяВременногоКаталога = ФайловаяСистема.СоздатьВременныйКаталог();
	СоздатьКаталог(ИмяВременногоКаталога);
	
	Для Каждого Файл Из СписокФайлов Цикл
		ИмяФайла = ИмяВременногоКаталога + Файл.ИмяФайла;
		ИмяФайла = ФайловаяСистема.УникальноеИмяФайла(ИмяФайла);
		Файл.ДвоичныеДанные.Записать(ИмяФайла);
		ЗаписьZipФайла.Добавить(ИмяФайла);
	КонецЦикла;
	
	ЗаписьZipФайла.Записать();
	ПотокВПамяти.Перейти(0, ПозицияВПотоке.Начало);
	
	ЧтениеДанных = Новый ЧтениеДанных(ПотокВПамяти);
	РезультатЧтенияДанных = ЧтениеДанных.Прочитать();
	ДвоичныеДанные = РезультатЧтенияДанных.ПолучитьДвоичныеДанные();
	
	ЧтениеДанных.Закрыть();
	ПотокВПамяти.Закрыть();
	
	ФайловаяСистема.УдалитьВременныйКаталог(ИмяВременногоКаталога);
	
	Возврат ДвоичныеДанные;
	
КонецФункции

// Параметры:
//   ТабличныйДокумент - ТабличныйДокумент
//   Формат - ТипФайлаТабличногоДокумента
// Возвращаемое значение:
//   ДвоичныеДанные
//
Функция ТабличныйДокументВДвоичныеДанные(ТабличныйДокумент, Формат)
	
	ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
	ТабличныйДокумент.Записать(ИмяВременногоФайла, Формат);
	
	Если Формат = ТипФайлаТабличногоДокумента.HTML Тогда
		ВставитьКартинкиВHTML(ИмяВременногоФайла);
	КонецЕсли;
	
	ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
	УдалитьФайлы(ИмяВременногоФайла);
	
	Возврат ДвоичныеДанные;
	
КонецФункции

Функция ПечатныеФормыПоОбъектам(ПечатнаяФорма, ОбъектыПечати) Экспорт
	
	Если ОбъектыПечати.Количество() = 0 Тогда
		Возврат Новый Структура("ОбъектыПечатиНеЗаданы", ПечатнаяФорма);
	КонецЕсли;
	
	Результат = Новый Соответствие;
	
	Для Каждого ОбъектПечати Из ОбъектыПечати Цикл
		ИмяОбласти = ОбъектПечати.Представление;
		Область = ПечатнаяФорма.Области.Найти(ИмяОбласти);
		Если Область = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если ОбъектыПечати.Количество() = 1 Тогда
			ТабличныйДокумент = ПечатнаяФорма;
		Иначе
			ТабличныйДокумент = ПечатнаяФорма.ПолучитьОбласть(Область.Верх, , Область.Низ);
			ПоследняяСтрока = ТабличныйДокумент.Область(ТабличныйДокумент.ВысотаТаблицы, , ТабличныйДокумент.ВысотаТаблицы, );
			ПоследняяСтрока.КонецСтраницы = Ложь;
			ЗаполнитьЗначенияСвойств(ТабличныйДокумент, ПечатнаяФорма, КопируемыеСвойстваТабличногоДокумента());
		КонецЕсли;
		
		Результат.Вставить(ОбъектПечати.Значение, ТабличныйДокумент);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ИмяФайлаПечатнойФормыОбъекта(ОбъектПечати, ИмяФайлаПечатнойФормы, НазваниеПечатнойФормы) Экспорт
	
	Если ОбъектПечати = Неопределено Или ОбъектПечати = "ОбъектыПечатиНеЗаданы" Тогда
		Если ЗначениеЗаполнено(НазваниеПечатнойФормы) Тогда
			Возврат НазваниеПечатнойФормы;
		КонецЕсли;
		Возврат НСтр("ru = 'Документ'");
	КонецЕсли;
	
	Если ТипЗнч(ИмяФайлаПечатнойФормы) = Тип("Соответствие") Тогда
		Возврат Строка(ИмяФайлаПечатнойФормы[ОбъектПечати]);
	ИначеЕсли ТипЗнч(ИмяФайлаПечатнойФормы) = Тип("Строка") И Не ПустаяСтрока(ИмяФайлаПечатнойФормы) Тогда
		Возврат ИмяФайлаПечатнойФормы;
	КонецЕсли;
	
	Возврат ИмяФайлаПечатнойФормыПоУмолчанию(ОбъектПечати, НазваниеПечатнойФормы);
	
КонецФункции

Функция ИмяФайлаПечатнойФормыПоУмолчанию(ОбъектПечати, НазваниеПечатнойФормы)
	
	ЭтоДокумент = ОбщегоНазначения.ЭтоДокумент(Метаданные.НайтиПоТипу(ТипЗнч(ОбъектПечати)));
	
	Если ЭтоДокумент Тогда
		
		ДокументСодержитНомер = ОбъектПечати.Метаданные().ДлинаНомера > 0;
		
		Если ДокументСодержитНомер Тогда
			СписокРеквизитов = "Дата,Номер";
			Шаблон = НСтр("ru = '[НазваниеПечатнойФормы] № [Номер] от [Дата]'");
		Иначе
			СписокРеквизитов = "Дата";
			Шаблон = НСтр("ru = '[НазваниеПечатнойФормы] от [Дата]'");
		КонецЕсли;
		
		ПараметрыДляВставки = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ОбъектПечати, СписокРеквизитов);
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрефиксацияОбъектов") И ДокументСодержитНомер Тогда
			МодульПрефиксацияОбъектовКлиентСервер = ОбщегоНазначения.ОбщийМодуль("ПрефиксацияОбъектовКлиентСервер");
			ПараметрыДляВставки.Номер = МодульПрефиксацияОбъектовКлиентСервер.НомерНаПечать(ПараметрыДляВставки.Номер);
		КонецЕсли;
		ПараметрыДляВставки.Дата = Формат(ПараметрыДляВставки.Дата, "ДЛФ=D");
		ПараметрыДляВставки.Вставить("НазваниеПечатнойФормы", НазваниеПечатнойФормы);
		
	Иначе
		
		ПараметрыДляВставки = Новый Структура;
		ПараметрыДляВставки.Вставить("НазваниеПечатнойФормы",НазваниеПечатнойФормы);
		ПараметрыДляВставки.Вставить("ПредставлениеОбъекта", ОбщегоНазначения.ПредметСтрокой(ОбъектПечати));
		ПараметрыДляВставки.Вставить("ТекущаяДата",Формат(ТекущаяДатаСеанса(), "ДЛФ=D"));
		Шаблон = НСтр("ru = '[НазваниеПечатнойФормы] - [ПредставлениеОбъекта] - [ТекущаяДата]'");
		
	КонецЕсли;
	
	Результат = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ПараметрыДляВставки);
	
	Если ОбщегоНазначения.ЭтоLinuxСервер() И СтрДлина(Результат) > 120 Тогда
		Если ЭтоДокумент Тогда
			СокращаемоеПоле = "НазваниеПечатнойФормы";
		Иначе
			СокращаемоеПоле = "ПредставлениеОбъекта";
		КонецЕсли;
		ПараметрыДляВставки[СокращаемоеПоле] = Лев(ПараметрыДляВставки[СокращаемоеПоле],
			СтрДлина(ПараметрыДляВставки[СокращаемоеПоле]) - (СтрДлина(Результат) - 117)) + "...";
		Результат = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ПараметрыДляВставки);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ИмяФайлаОфисногоДокумента(Знач ИмяФайла, Знач ПереводитьВТранслит = Ложь) Экспорт
	
	ИмяФайла = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяФайла);
	
	ОжидаемыеРасширения = Новый Соответствие;
	ОжидаемыеРасширения.Вставить(".docx", Истина);
	ОжидаемыеРасширения.Вставить(".doc", Истина);
	ОжидаемыеРасширения.Вставить(".odt", Истина);
	ОжидаемыеРасширения.Вставить(".html", Истина);
	
	Файл = Новый Файл(ИмяФайла);
	Если ОжидаемыеРасширения[Файл.Расширение] = Неопределено Тогда
		ИмяФайла = ИмяФайла + ".docx";
	КонецЕсли;
	
	Если ПереводитьВТранслит Тогда
		ИмяФайла = СтроковыеФункции.СтрокаЛатиницей(ИмяФайла)
	КонецЕсли;
	
	Возврат ИмяФайла;
	
КонецФункции

// Список возможных имен макета:
//  1) на языке сеанса,
//  2) на языке конфигурации,
//  3) без указания языка.
//
Функция ИменаМакета(Знач ИмяМакета, Знач КодЯзыка = Неопределено)
	
	Результат = Новый Массив;
	
	Если ЗначениеЗаполнено(КодЯзыка) Тогда
		Результат.Добавить(ИмяМакета + "_" + КодЯзыка);
		ЧастиСтроки = СтрРазделить(КодЯзыка, "_", Ложь);
		Если ЧастиСтроки.Количество() > 1 Тогда
			Результат.Добавить(ИмяМакета + "_" + ЧастиСтроки[0]);
		КонецЕсли;
	КонецЕсли;
	
	Результат.Добавить(ИмяМакета + "_" + ОбщегоНазначения.КодОсновногоЯзыка());
	Результат.Добавить(ИмяМакета);
	
	Возврат Результат;
	
КонецФункции

// Конструктор для параметра КоллекцияПечатныхФорм процедуры Печать.
//
// Возвращаемое значение:
//  ТаблицаЗначений - пустая коллекция печатных форм:
//   * ИмяМакета - Строка - идентификатор печатной формы;
//   * ИмяВРЕГ - Строка - идентификатор в верхнем регистре символов для быстрого поиска;
//   * СинонимМакета - Строка - представление печатной формы;
//   * ТабличныйДокумент - ТабличныйДокумент - печатная форма;
//   * Экземпляров - Число - количество копий, которое необходимо вывести на печать;
//   * Картинка - Картинка - (не используется);
//   * ПолныйПутьКМакету - Строка - используется для быстрого перехода к редактированию макета печатной формы;
//   * ИмяФайлаПечатнойФормы - Строка - имя файла;
//                           - Соответствие из КлючИЗначение - имена файлов для каждого объекта:
//                              ** Ключ - ЛюбаяСсылка - ссылка на объект печати;
//                              ** Значение - Строка - имя файла;
//   * ОфисныеДокументы - Соответствие из КлючИЗначение - коллекция печатных форм в формате офисных документов:
//                         ** Ключ - Строка - адрес во временном хранилище двоичных данных печатной формы;
//                         ** Значение - Строка - имя файла печатной формы.
//
Функция ПодготовитьКоллекциюПечатныхФорм(Знач Идентификаторы) Экспорт
	
	Результат = Новый ТаблицаЗначений;
	Для Каждого ИмяКолонки Из УправлениеПечатьюКлиентСервер.ИменаПолейКоллекцииПечатныхФорм() Цикл
		Результат.Колонки.Добавить(ИмяКолонки);
	КонецЦикла;
	
	Если ТипЗнч(Идентификаторы) = Тип("Строка") Тогда
		Идентификаторы = СтрРазделить(Идентификаторы, ",");
	КонецЕсли;
	
	Для Каждого Идентификатор Из Идентификаторы Цикл
		ПечатнаяФорма = Результат.Найти(Идентификатор, "ИмяМакета");
		Если ПечатнаяФорма = Неопределено Тогда
			ПечатнаяФорма = Результат.Добавить();
			ПечатнаяФорма.ИмяМакета = Идентификатор;
			ПечатнаяФорма.ИмяВРЕГ = ВРег(Идентификатор);
			ПечатнаяФорма.Экземпляров = 1;
		Иначе
			ПечатнаяФорма.Экземпляров = ПечатнаяФорма.Экземпляров + 1;
		КонецЕсли;
	КонецЦикла;
	
	Результат.Индексы.Добавить("ИмяВРЕГ");
	Возврат Результат;
	
КонецФункции

// Подготовить структуру параметров вывода для менеджера объекта формирующего печатные формы.
//
// Возвращаемое значение:
//  Структура:
//   * ПараметрыОтправки - Структура:
//     ** Получатель - Неопределено, Произвольный
//     ** Тема - Строка
//     ** Текст - Строка
//   * КодЯзыка - Строка
//   * ДоступнаПечатьПоКомплектно - Булево
//   * ЗаголовокФормы - Строка
//
Функция ПодготовитьСтруктуруПараметровВывода() Экспорт
	
	ПараметрыВывода = Новый Структура;
	ПараметрыВывода.Вставить("ЗаголовокФормы", "");
	ПараметрыВывода.Вставить("ДоступнаПечатьПоКомплектно", Ложь); // не используется
	ПараметрыВывода.Вставить("КодЯзыка", ОбщегоНазначения.КодОсновногоЯзыка());
	
	СтруктураПараметровПисьма = Новый Структура("Получатель,Тема,Текст", Неопределено, "", "");
	ПараметрыВывода.Вставить("ПараметрыОтправки", СтруктураПараметровПисьма);
	
	Возврат ПараметрыВывода;
	
КонецФункции

// Параметры:
//  КомандаПечати - СтрокаТаблицыЗначений из см. СоздатьКоллекциюКомандПечати
//  НастройкиСохранения - см. УправлениеПечатью.НастройкиСохранения
//  СписокОбъектов - Массив
//  Результат - ТаблицаЗначений:
//   * ИмяФайла - Строка
//   * ДвоичныеДанные - ДвоичныеДанные
//
Процедура ВыполнитьКомандуПечатиВФайл(КомандаПечати, НастройкиСохранения, СписокОбъектов, Результат)
	
	Если Не ЗначениеЗаполнено(НастройкиСохранения.ФорматыСохранения) Тогда
		НастройкиСохранения.ФорматыСохранения.Добавить(СтандартныеПодсистемыСервер.ТипФайлаТабличногоДокументаPDF());
	КонецЕсли;
	
	ДанныеПечати = Неопределено;
	Если КомандаПечати.МенеджерПечати = "СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки" Тогда
		Источник = КомандаПечати.ДополнительныеПараметры.Ссылка;
		ДанныеПечати = СформироватьВнешнююПечатнуюФорму(Источник, КомандаПечати.Идентификатор, СписокОбъектов);
	Иначе
		ДанныеПечати = СформироватьПечатныеФормы(КомандаПечати.МенеджерПечати, КомандаПечати.Идентификатор,
		СписокОбъектов, КомандаПечати.ДополнительныеПараметры);
	КонецЕсли;
	
	КоллекцияПечатныхФорм = ДанныеПечати.КоллекцияПечатныхФорм;
	ОбъектыПечати = ДанныеПечати.ОбъектыПечати;
	
	ПодписиИПечатиОбластей = Неопределено;
	Если НастройкиСохранения.ПодписьИПечать Тогда
		ПодписиИПечатиОбластей = ПодписиИПечатиОбластей(ОбъектыПечати);
	КонецЕсли;
	
	ТаблицаФорматов = НастройкиФорматовСохраненияТабличногоДокумента();
	
	Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
		Если ЗначениеЗаполнено(ПечатнаяФорма.ОфисныеДокументы) Тогда
			Для Каждого ОфисныйДокумент Из ПечатнаяФорма.ОфисныеДокументы Цикл
				Файл = Результат.Добавить();
				Файл.ИмяФайла = ИмяФайлаОфисногоДокумента(ОфисныйДокумент.Значение, НастройкиСохранения.ПереводитьИменаФайловВТранслит);
				Файл.ДвоичныеДанные = ПолучитьИзВременногоХранилища(ОфисныйДокумент.Ключ);
			КонецЦикла;
			Продолжить;
		КонецЕсли;
		
		Если НастройкиСохранения.ПодписьИПечать Тогда
			ДобавитьПодписьИПечать(ПечатнаяФорма.ТабличныйДокумент, ПодписиИПечатиОбластей);
		Иначе
			УбратьПодписьИПечать(ПечатнаяФорма.ТабличныйДокумент);
		КонецЕсли;
		
		ПечатныеФормыПоОбъектам = ПечатныеФормыПоОбъектам(ПечатнаяФорма.ТабличныйДокумент, ОбъектыПечати);
		Для Каждого СоответствиеОбъектаПечатнойФорме Из ПечатныеФормыПоОбъектам Цикл
			
			ОбъектПечати = СоответствиеОбъектаПечатнойФорме.Ключ;
			ТабличныйДокумент = СоответствиеОбъектаПечатнойФорме.Значение;
			
			Если ТабличныйДокумент.ВысотаТаблицы = 0 Тогда
				Продолжить;
			КонецЕсли;
			
			Для Каждого Формат Из НастройкиСохранения.ФорматыСохранения Цикл
				ТипФайла = Формат;
				Если ТипЗнч(ТипФайла) = Тип("Строка") Тогда
					ТипФайла = ТипФайлаТабличногоДокумента[ТипФайла];
				КонецЕсли;
				ТипФайла = ИспользуемыйТипФайлаТабличногоДокумента(ТипФайла);
				
				НастройкиФормата = ТаблицаФорматов.НайтиСтроки(Новый Структура("ТипФайлаТабличногоДокумента", ТипФайла))[0];
				
				РасширениеФайла = НастройкиФормата.Расширение;
				ЗаданныеИменаПечатныхФорм = ПечатнаяФорма.ИмяФайлаПечатнойФормы;
				НазваниеПечатнойФормы = ПечатнаяФорма.СинонимМакета;
				
				ИмяФайла = ИмяФайлаПечатнойФормыОбъекта(ОбъектПечати, ЗаданныеИменаПечатныхФорм, НазваниеПечатнойФормы) + "." + РасширениеФайла;
				Если НастройкиСохранения.ПереводитьИменаФайловВТранслит Тогда
					ИмяФайла = СтроковыеФункции.СтрокаЛатиницей(ИмяФайла)
				КонецЕсли;
				ИмяФайла = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяФайла);
				
				Файл = Результат.Добавить();
				Файл.ИмяФайла = ИмяФайла;
				Файл.ДвоичныеДанные = ТабличныйДокументВДвоичныеДанные(ТабличныйДокумент, ТипФайла);
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;

КонецПроцедуры

Функция ИспользуемыйТипФайлаТабличногоДокумента(ТипФайла)
	
	Если ТипФайла = ТипФайлаТабличногоДокумента.PDF
		Или Строка(ТипФайла) = "PDF_A_1"
		Или Строка(ТипФайла) = "PDF_A_2"
		Или Строка(ТипФайла) = "PDF_A_3" Тогда
		Возврат СтандартныеПодсистемыСервер.ТипФайлаТабличногоДокументаPDF();
	КонецЕсли;
	
	ЗаменяемыеТипы = Новый Соответствие;
	ЗаменяемыеТипы.Вставить(ТипФайлаТабличногоДокумента.HTML, ТипФайлаТабличногоДокумента.HTML5);
	ЗаменяемыеТипы.Вставить(ТипФайлаТабличногоДокумента.HTML3, ТипФайлаТабличногоДокумента.HTML5);
	ЗаменяемыеТипы.Вставить(ТипФайлаТабличногоДокумента.HTML4, ТипФайлаТабличногоДокумента.HTML5);
	ЗаменяемыеТипы.Вставить(ТипФайлаТабличногоДокумента.MXL7, ТипФайлаТабличногоДокумента.MXL);
	ЗаменяемыеТипы.Вставить(ТипФайлаТабличногоДокумента.XLS95, ТипФайлаТабличногоДокумента.XLS);
	ЗаменяемыеТипы.Вставить(ТипФайлаТабличногоДокумента.XLS97, ТипФайлаТабличногоДокумента.XLS);
	
	Результат = ЗаменяемыеТипы[ТипФайла];
	Если Результат = Неопределено Тогда
		Результат = ТипФайла;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция МакетыПечатныхФорм(ТолькоОбработкиИОтчеты = Ложь) Экспорт
	
	Результат = Новый Соответствие;
	
	КоллекцииОбъектовМетаданных = Новый Массив; // Массив из КоллекцияОбъектовМетаданных -
	КоллекцииОбъектовМетаданных.Добавить(Метаданные.Обработки);
	КоллекцииОбъектовМетаданных.Добавить(Метаданные.Отчеты);
	Если Не ТолькоОбработкиИОтчеты Тогда
		КоллекцииОбъектовМетаданных.Добавить(Метаданные.Справочники);
		КоллекцииОбъектовМетаданных.Добавить(Метаданные.Документы);
		КоллекцииОбъектовМетаданных.Добавить(Метаданные.БизнесПроцессы);
		КоллекцииОбъектовМетаданных.Добавить(Метаданные.Задачи);
		КоллекцииОбъектовМетаданных.Добавить(Метаданные.ЖурналыДокументов);
	КонецЕсли;
	
	Для Каждого КоллекцияОбъектовМетаданных Из КоллекцииОбъектовМетаданных Цикл
		Для Каждого ОбъектМетаданныхКоллекции Из КоллекцияОбъектовМетаданных Цикл
			ОбъектМетаданных = ОбъектМетаданныхКоллекции; // ОбъектМетаданныхДокумент - 
			Для Каждого Макет Из ОбъектМетаданных.Макеты Цикл
				Если СтрНайти(Макет.Имя, "ПФ_") > 0 Тогда
					Если (КоллекцияОбъектовМетаданных = Метаданные.Обработки Или КоллекцияОбъектовМетаданных = Метаданные.Отчеты)
						И Не ПравоДоступа("Просмотр", ОбъектМетаданных) Тогда
						Продолжить;
					КонецЕсли;
					Результат.Вставить(Макет, ОбъектМетаданных);
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	Для Каждого Макет Из Метаданные.ОбщиеМакеты Цикл
		Если СтрНайти(Макет.Имя, "ПФ_") > 0 Тогда
			Результат.Вставить(Макет, Метаданные.ОбщиеМакеты);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  ТабличныйДокумент, ДвоичныеДанные - макет.
//
Функция НайтиМакет(ПутьКМакету, КодЯзыка, ТолькоПоставляемый = Ложь)
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Макет ""%1"" не существует. Операция прервана.'"), ПутьКМакету);
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	
	НайденныйМакет = Справочники.МакетыПечатныхФорм.НайтиМакет(ПутьКМакету, КодЯзыка);
	Если НайденныйМакет <> Неопределено Тогда
		Возврат НайденныйМакет;
	КонецЕсли;

	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	ИмяМакета = ЧастиПути[ЧастиПути.ВГраница()];
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ПользовательскиеМакетыПечати.Макет КАК Макет,
	|	ПользовательскиеМакетыПечати.ИмяМакета КАК ИмяМакета
	|ИЗ
	|	РегистрСведений.ПользовательскиеМакетыПечати КАК ПользовательскиеМакетыПечати
	|ГДЕ
	|	ПользовательскиеМакетыПечати.Объект = &Объект
	|	И ПользовательскиеМакетыПечати.ИмяМакета ПОДОБНО &ИмяМакета
	|	И ПользовательскиеМакетыПечати.Использование";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.Параметры.Вставить("Объект", ИмяОбъекта);
	Запрос.Параметры.Вставить("ИмяМакета", ИмяМакета + "%");
	
	СписокМакетов = Новый Соответствие;
	
	Если Не ТолькоПоставляемый Тогда
		Выборка = Запрос.Выполнить().Выбрать();
		Пока Выборка.Следующий() Цикл
			СписокМакетов.Вставить(Выборка.ИмяМакета, Выборка.Макет.Получить());
		КонецЦикла;
	КонецЕсли;
	
	ИменаПоиска = ИменаМакета(ИмяМакета, КодЯзыка);
	
	Для Каждого ИмяПоиска Из ИменаПоиска Цикл
		НайденныйМакет = СписокМакетов[ИмяПоиска];
		Если НайденныйМакет <> Неопределено Тогда
			УстановитьЯзыкМакета(НайденныйМакет, КодЯзыка);
			Возврат НайденныйМакет;
		КонецЕсли;
	КонецЦикла;
	
	ЭтоОбщийМакет = СтрРазделить(ИмяОбъекта, ".").Количество() = 1;
	
	КоллекцияМакетов = Метаданные.ОбщиеМакеты;
	Если Не ЭтоОбщийМакет Тогда
		ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта);
		Если ОбъектМетаданных = Неопределено Тогда
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		КоллекцияМакетов = ОбъектМетаданных.Макеты;
	КонецЕсли;
	
	Для Каждого ИмяПоиска Из ИменаПоиска Цикл
		Если КоллекцияМакетов.Найти(ИмяПоиска) <> Неопределено Тогда
			Если ЭтоОбщийМакет Тогда
				Макет = ПолучитьОбщийМакет(ИмяПоиска);
			Иначе
				УстановитьОтключениеБезопасногоРежима(Истина);
				УстановитьПривилегированныйРежим(Истина);
				Макет = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИмяОбъекта).ПолучитьМакет(ИмяПоиска);
			КонецЕсли;
			УстановитьЯзыкМакета(Макет, КодЯзыка);
			Возврат Макет;
		КонецЕсли;
	КонецЦикла;
	
	ВызватьИсключение ТекстОшибки;
	
КонецФункции

Процедура УстановитьЯзыкМакета(Макет, КодЯзыка)
	
	Если ТипЗнч(Макет) <> Тип("ТабличныйДокумент") Тогда
		Возврат;
	КонецЕсли;
	
	ЭтоДополнительныйЯзыкПечатныхФорм = Ложь;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность.Печать") Тогда
		МодульУправлениеПечатьюМультиязычность = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатьюМультиязычность");
		ЭтоДополнительныйЯзыкПечатныхФорм = МодульУправлениеПечатьюМультиязычность.ЭтоДополнительныйЯзыкПечатныхФорм(КодЯзыка);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(КодЯзыка) И Не ЭтоДополнительныйЯзыкПечатныхФорм Тогда
		Макет.КодЯзыка = КодЯзыка;
	Иначе
		Макет.КодЯзыка = ОбщегоНазначения.КодОсновногоЯзыка();
	КонецЕсли;
	
КонецПроцедуры

// Формирует печатные формы.
//
// Параметры:
//  МассивОбъектов - см. УправлениеПечатьюПереопределяемый.ПриПечати.МассивОбъектов
//  ПараметрыПечати - см. УправлениеПечатьюПереопределяемый.ПриПечати.ПараметрыПечати
//  КоллекцияПечатныхФорм - см. УправлениеПечатьюПереопределяемый.ПриПечати.КоллекцияПечатныхФорм
//  ОбъектыПечати - см. УправлениеПечатьюПереопределяемый.ПриПечати.ОбъектыПечати
//  ПараметрыВывода - см. УправлениеПечатьюПереопределяемый.ПриПечати.ПараметрыВывода
//
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода)
	
	КодЯзыка = ПараметрыВывода.КодЯзыка;
	
	МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоСсылке(МассивОбъектов[0]);	
	Если НастройкиПечатиОбъекта(МенеджерОбъекта).ПриОпределенииПолучателей Тогда
		МенеджерОбъекта.ПриОпределенииПолучателей(ПараметрыВывода.ПараметрыОтправки, МассивОбъектов, КоллекцияПечатныхФорм);
	КонецЕсли;
		
	Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
		ПечатнаяФорма.ДоступенВыводНаДругихЯзыках = Истина;
		ПечатнаяФорма.ПолныйПутьКМакету = ПечатнаяФорма.ИмяМакета;
		ПечатнаяФорма.СинонимМакета = ПредставлениеМакета(ПечатнаяФорма.ПолныйПутьКМакету, КодЯзыка);
		// @skip-check query-in-loop - Небольшое количество итераций цикла с запросом к таблице РегистрСведений.ПользовательскиеМакетыПечати 
		// с заведомо небольшим количеством записей
		Макет = МакетПечатнойФормы(ПечатнаяФорма.ПолныйПутьКМакету, КодЯзыка); 
		
		Если ТипЗнч(Макет) = Тип("ДвоичныеДанные") Тогда
			ПечатнаяФорма.ОфисныеДокументы = СформироватьОфисныйДокумент(Макет, МассивОбъектов, ОбъектыПечати, КодЯзыка, ПараметрыПечати);
		Иначе			
			ТабличныйДокумент = СформироватьТабличныйДокумент(Макет, МассивОбъектов, ОбъектыПечати, КодЯзыка); // ТабличныйДокумент
			ТабличныйДокумент.КлючПараметровПечати = ПечатнаяФорма.ПолныйПутьКМакету + ?(ЗначениеЗаполнено(КодЯзыка), "." + КодЯзыка, "");
			ПечатнаяФорма.ТабличныйДокумент = ТабличныйДокумент;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ЗаменитьПараметрыЗначениями(Знач Строка, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка)
	
	ПараметрыТекста = НайтиПараметрыВТексте(Строка(Строка));
	ЗначенияПараметров = ЗначенияПараметров(ПараметрыТекста, ИсточникДанных, НастройкиФорматаПолей, КодЯзыка);
	
	Если ТипЗнч(Строка) = Тип("ФорматированнаяСтрока") Тогда
		Результат = ЗаменитьВФорматированнойСтроке(Строка, ЗначенияПараметров);
	Иначе
		Результат = ЗаменитьВСтроке(Строка, ЗначенияПараметров);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ЗаменитьВСтроке(Знач Строка, ПараметрыЗамены)
	
	Для Каждого Элемент Из ПараметрыЗамены Цикл
		ПодстрокаПоиска = Элемент.Ключ;
		ПодстрокаЗамены = Элемент.Значение;
		Строка = СтрЗаменить(Строка, ПодстрокаПоиска, ПодстрокаЗамены);
	КонецЦикла;
	
	Возврат Строка;
	
КонецФункции

Функция ЗаменитьВФорматированнойСтроке(Строка, ПараметрыЗамены)

	ФорматированныйДокумент = Новый ФорматированныйДокумент;
	ФорматированныйДокумент.УстановитьФорматированнуюСтроку(Строка);
	
	Для Каждого Элемент Из ПараметрыЗамены Цикл
		ПодстрокаПоиска = Элемент.Ключ;
		ПодстрокаЗамены = Элемент.Значение;

		НайденнаяОбласть = ФорматированныйДокумент.НайтиТекст(ПодстрокаПоиска);
		Пока НайденнаяОбласть <> Неопределено Цикл
			Фрагменты = ФорматированныйДокумент.СформироватьЭлементы(НайденнаяОбласть.ЗакладкаНачала, НайденнаяОбласть.ЗакладкаКонца);
			Для Индекс = 1 По Фрагменты.ВГраница() Цикл
				Фрагменты[0].Текст = Фрагменты[0].Текст + Фрагменты[Индекс].Текст;
				Фрагменты[Индекс].Текст = "";
			КонецЦикла;
			Фрагменты[0].Текст = СтрЗаменить(Фрагменты[0].Текст, ПодстрокаПоиска, ПодстрокаЗамены);
	
			НайденнаяОбласть = ФорматированныйДокумент.НайтиТекст(ПодстрокаПоиска, НайденнаяОбласть.ЗакладкаКонца);
		КонецЦикла;
	КонецЦикла;
	
	Возврат ФорматированныйДокумент.ПолучитьФорматированнуюСтроку();

КонецФункции

Процедура ЗаполнитьДанныеПечати(ДанныеПечати, ОписаниеПолей, ИерархияПолей, Объекты, КодЯзыка)
	
	Если ДанныеПечати["ИменаТабличныхЧастейОбъекта"] = Неопределено Тогда
		ДанныеПечати["ИменаТабличныхЧастейОбъекта"] = Новый Массив;
	КонецЕсли;

	Если ДанныеПечати["НастройкиФорматаПолей"] = Неопределено Тогда
		ДанныеПечати["НастройкиФорматаПолей"] = Новый Соответствие;
	КонецЕсли;

	Для Каждого КоллекцияПолей Из ИерархияПолей Цикл
		ПодчиненныеПоля = КоллекцияПолей.Значение;
		Если Не ЗначениеЗаполнено(ПодчиненныеПоля) Тогда
			Продолжить;
		КонецЕсли;
		
		ИсточникПолей = КоллекцияПолей.Ключ;
		ПутьКДаннымТабличнойЧасти = "";
		ПутьКДаннымИсточникаПолей = ИсточникПолей;
		ПутьКДаннымВладельцаИсточника = ПутьКДаннымВладельцаПоля(ПутьКДаннымИсточникаПолей, ОписаниеПолей);
		
		ИсточникПолейВТабличнойЧасти = ЭтоПолеТабличнойЧасти(ПутьКДаннымИсточникаПолей, ДанныеПечати);
		Если ИсточникПолейВТабличнойЧасти Тогда
			ПутьКДаннымТабличнойЧасти = ПутьКДаннымТабличнойЧасти(ПутьКДаннымИсточникаПолей, ДанныеПечати);
			ПутьКДаннымИсточникаПолей = ПутьКДаннымПоляВТабличнойЧасти(ПутьКДаннымИсточникаПолей, ДанныеПечати);
		КонецЕсли;
		
		ВладелецИсточникаВТабличнойЧасти = ЭтоПолеТабличнойЧасти(ПутьКДаннымВладельцаИсточника, ДанныеПечати);
		Если ИсточникПолейВТабличнойЧасти И ВладелецИсточникаВТабличнойЧасти Тогда
			ПутьКДаннымВладельцаИсточника = ПутьКДаннымПоляВТабличнойЧасти(ПутьКДаннымВладельцаИсточника, ДанныеПечати);
		КонецЕсли;
		
		Поля = Новый Соответствие;
		СхемыКомпоновкиДанных = Новый Соответствие;
		
		Для Каждого Поле Из ПодчиненныеПоля Цикл
			ОписаниеПоля = ОписаниеПолей.НайтиСтроки(Новый Структура("Поле", Поле.Ключ))[0];
			СхемаКомпоновкиДанных = ОписаниеПоля.СхемаКомпоновкиДанных;
			СхемыКомпоновкиДанных.Вставить(СхемаКомпоновкиДанных, ОписаниеПоля.ИдентификаторСхемыКомпоновкиДанных);
			Если Поля[СхемаКомпоновкиДанных] = Неопределено Тогда
				Поля[СхемаКомпоновкиДанных] = Новый Массив;
			КонецЕсли;
			ПоляСхемыКомпоновкиДанных = Поля[СхемаКомпоновкиДанных]; // Массив
			ПоляСхемыКомпоновкиДанных.Добавить(ОписаниеПоля.ПутьКДанным);
			
			Если ЗначениеЗаполнено(ОписаниеПоля.Формат) Тогда
				ДанныеПечати["НастройкиФорматаПолей"][ОписаниеПоля.Поле] = ОписаниеПоля.Формат;
			КонецЕсли;
		КонецЦикла;
		
		ОписанияИсточниковДанных = Новый ТаблицаЗначений;
		ОписанияИсточниковДанных.Колонки.Добавить("Владелец");
		ОписанияИсточниковДанных.Колонки.Добавить("Имя");
		ОписанияИсточниковДанных.Колонки.Добавить("Значение");
		
		Для Каждого Объект Из Объекты Цикл
			Если ИсточникПолейВТабличнойЧасти Тогда
				Если ЭтоПолеТабличнойЧасти(ПутьКДаннымТабличнойЧасти, ДанныеПечати) Тогда
					Продолжить;
				КонецЕсли;
				Для НомерСтроки = 1 По ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти].Количество() Цикл
					ЗначениеИсточникаПолей = ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти][НомерСтроки][ПутьКДаннымИсточникаПолей];
					Если ЗначениеЗаполнено(ЗначениеИсточникаПолей) Тогда
						ОписаниеИсточника = ОписанияИсточниковДанных.Добавить();
						Если ВладелецИсточникаВТабличнойЧасти Тогда
							ОписаниеИсточника.Владелец = ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти][НомерСтроки][ПутьКДаннымВладельцаИсточника];
						Иначе
							Если ЗначениеЗаполнено(ПутьКДаннымВладельцаИсточника) Тогда
								ОписаниеИсточника.Владелец = ДанныеПечати[Объект][ПутьКДаннымВладельцаИсточника];
							ИначеЕсли ПутьКДаннымИсточникаПолей <> "Ссылка" Тогда
								ОписаниеИсточника.Владелец = Объект;
							КонецЕсли;
						КонецЕсли;
						ОписаниеИсточника.Имя = ИмяПоля(ПутьКДаннымИсточникаПолей);
						ОписаниеИсточника.Значение = ЗначениеИсточникаПолей;
					Иначе
						Для Каждого Поле Из ПодчиненныеПоля Цикл
							ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти][НомерСтроки][ПутьКДаннымПоляВТабличнойЧасти(Поле.Ключ, ДанныеПечати)] = Неопределено;
						КонецЦикла;
					КонецЕсли;
				КонецЦикла;
			Иначе
				Если ИсточникПолей = "Ссылка" Тогда
					ЗначениеИсточникаПолей = Объект;
				Иначе
					ЗначениеИсточникаПолей = ДанныеПечати[Объект][ПутьКДаннымИсточникаПолей];
				КонецЕсли;
				Если ЗначениеЗаполнено(ЗначениеИсточникаПолей) Тогда
					ОписаниеИсточника = ОписанияИсточниковДанных.Добавить();
					Если ЗначениеЗаполнено(ПутьКДаннымВладельцаИсточника) Тогда
						ОписаниеИсточника.Владелец = ДанныеПечати[Объект][ПутьКДаннымВладельцаИсточника];
					ИначеЕсли ПутьКДаннымИсточникаПолей <> "Ссылка" Тогда
						ОписаниеИсточника.Владелец = Объект;
					КонецЕсли;
					ОписаниеИсточника.Имя = ИмяПоля(ПутьКДаннымИсточникаПолей);
					ОписаниеИсточника.Значение = ЗначениеИсточникаПолей;
				Иначе
					Для Каждого Поле Из ПодчиненныеПоля Цикл
						ДанныеПечати[Объект][Поле.Ключ] = Неопределено;
					КонецЦикла;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
		Для Каждого Элемент Из Поля Цикл
			ИдентификаторСхемыКомпоновкиДанных = СхемыКомпоновкиДанных[Элемент.Ключ];
			СхемаКомпоновкиДанных = ПолучитьИзВременногоХранилища(Элемент.Ключ);
			ПоляСхемы = Элемент.Значение;
			
			ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = Ложь;
			ИсточникиДанных = ОписанияИсточниковДанных.ВыгрузитьКолонку("Значение");
			
			Для Индекс = 0 По ИсточникиДанных.ВГраница() Цикл
				Если ИсточникиДанных[Индекс] = Неопределено Тогда
					ИсточникиДанных[Индекс] = "";
				КонецЕсли;
			КонецЦикла;
			
			ИсточникиДанных = ОбщегоНазначенияКлиентСервер.СвернутьМассив(ИсточникиДанных);
			
			Параметры = КоллекцияПараметровПолученияДанныхИсточников();
			Параметры.ИсточникиДанных = ИсточникиДанных;
			Параметры.ПоляСхемы = ПоляСхемы;
			Параметры.КодЯзыка = КодЯзыка;
			Параметры.СхемаКомпоновкиДанных = СхемаКомпоновкиДанных;
			Параметры.ИдентификаторСхемыКомпоновкиДанных = ИдентификаторСхемыКомпоновкиДанных;
			Параметры.ОписанияИсточниковДанных = ОписанияИсточниковДанных;
			Параметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных;
			
			ДанныеИсточников = ДанныеИсточников(Параметры);
			
			ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = Параметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных;
			
			Если ДанныеИсточников["ИменаТабличныхЧастейОбъекта"] <> Неопределено Тогда
				Для Каждого ИмяТабличнойЧасти Из ДанныеИсточников["ИменаТабличныхЧастейОбъекта"] Цикл
					Если ИсточникПолей = "Ссылка" Тогда
						ДанныеПечати["ИменаТабличныхЧастейОбъекта"].Добавить(ИмяТабличнойЧасти);
					Иначе
						ДанныеПечати["ИменаТабличныхЧастейОбъекта"].Добавить(ИсточникПолей + "." + ИмяТабличнойЧасти);
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
			
			Для Каждого Объект Из Объекты Цикл
				Если ИсточникПолейВТабличнойЧасти Тогда
					Если ЭтоПолеТабличнойЧасти(ПутьКДаннымТабличнойЧасти, ДанныеПечати) Тогда
						Продолжить;
					КонецЕсли;
					Для НомерСтроки = 1 По ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти].Количество() Цикл
						Если ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных Тогда
							Если ВладелецИсточникаВТабличнойЧасти Тогда
								ИсточникДанных = ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти][НомерСтроки][ПутьКДаннымВладельцаИсточника];
							Иначе
								Если ЗначениеЗаполнено(ПутьКДаннымВладельцаИсточника) Тогда
									ИсточникДанных = ДанныеПечати[Объект][ПутьКДаннымВладельцаИсточника];
								Иначе
									ИсточникДанных = Объект;
								КонецЕсли;
							КонецЕсли;
						Иначе
							ИсточникДанных = ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти][НомерСтроки][ПутьКДаннымИсточникаПолей];
						КонецЕсли;
						Если ИсточникДанных = Неопределено Тогда
							ИсточникДанных = "";
						КонецЕсли;
						
						Если ДанныеИсточников[ИсточникДанных] <> Неопределено Тогда
							Для Каждого ДанныеПоля Из ДанныеИсточников[ИсточникДанных] Цикл
								Поле = ДанныеПоля.Ключ;
								ЗначениеПоля = ДанныеПоля.Значение;
								ДанныеПечати[Объект][ПутьКДаннымТабличнойЧасти][НомерСтроки][ПутьКДаннымИсточникаПолей + "." + Поле] = ЗначениеПоля;
							КонецЦикла;
						КонецЕсли;
					КонецЦикла;
				Иначе
					Если ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных Тогда
						Если ЗначениеЗаполнено(ПутьКДаннымВладельцаИсточника) Тогда
							ИсточникДанных = ДанныеПечати[Объект][ПутьКДаннымВладельцаИсточника];
						Иначе
							ИсточникДанных = Объект;
						КонецЕсли;
					ИначеЕсли ИсточникПолей = "Ссылка" Тогда
						ИсточникДанных = Объект;
					Иначе
						ИсточникДанных = ДанныеПечати[Объект][ПутьКДаннымИсточникаПолей];
					КонецЕсли;
					
					Если ИсточникДанных = Неопределено Тогда
						ИсточникДанных = "";
					КонецЕсли;
					
					Если ДанныеИсточников[ИсточникДанных] <> Неопределено Тогда
						Для Каждого ДанныеПоля Из  ДанныеИсточников[ИсточникДанных] Цикл
							Поле = ДанныеПоля.Ключ;
							ЗначениеПоля = ДанныеПоля.Значение;
							
							Если ИсточникПолей = "Ссылка" Тогда
								ПутьКДаннымПоля = Поле;
							Иначе
								ПутьКДаннымПоля = ПутьКДаннымИсточникаПолей + "." + Поле;
							КонецЕсли;
							
							Если ДанныеПечати[Объект][ПутьКДаннымПоля] = Неопределено Тогда
								ДанныеПечати[Объект][ПутьКДаннымПоля] = ЗначениеПоля;
							ИначеЕсли ТипЗнч(ДанныеПечати[Объект][ПутьКДаннымПоля]) = Тип("Соответствие") И ТипЗнч(ЗначениеПоля) = Тип("Соответствие") Тогда
								Для Каждого СтрокаИсточник Из ЗначениеПоля Цикл
									СтрокаПриемник = ДанныеПечати[Объект][ПутьКДаннымПоля][СтрокаИсточник.Ключ];
									Если СтрокаПриемник = Неопределено Тогда
										СтрокаПриемник = Новый Соответствие;
										ДанныеПечати[Объект][ПутьКДаннымПоля][СтрокаИсточник.Ключ] = СтрокаПриемник;
									КонецЕсли;
									Для Каждого ПолеСтроки Из СтрокаИсточник.Значение Цикл
										СтрокаПриемник[ПолеСтроки.Ключ] = ПолеСтроки.Значение;
									КонецЦикла;
								КонецЦикла;
							КонецЕсли;
						КонецЦикла;
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
		ЗаполнитьДанныеПечати(ДанныеПечати, ОписаниеПолей, ПодчиненныеПоля, Объекты, КодЯзыка)
	КонецЦикла;
	
КонецПроцедуры

Функция ПутьКДаннымВладельцаПоля(ПутьКДаннымПоля, ОписаниеПолей)
	
	ПутьКДаннымВладельцаПоля = ПутьКДаннымРодителя(ПутьКДаннымПоля);
	Пока ЗначениеЗаполнено(ПутьКДаннымВладельцаПоля) Цикл
		ОписаниеПоля = ОписаниеПолей.НайтиСтроки(Новый Структура("Поле", ПутьКДаннымВладельцаПоля))[0];
		Если Не ОписаниеПоля.Папка И Не ОписаниеПоля.Таблица Тогда
			Возврат ПутьКДаннымВладельцаПоля;
		КонецЕсли;
		ПутьКДаннымВладельцаПоля = ПутьКДаннымРодителя(ПутьКДаннымВладельцаПоля);
	КонецЦикла;
	
	Возврат ПутьКДаннымВладельцаПоля;
	
КонецФункции

Функция ПутьКДаннымПоляВТабличнойЧасти(ПутьКДаннымПоля, ДанныеПечати)
	
	ПутьКДаннымТабличнойЧасти = ПутьКДаннымТабличнойЧасти(ПутьКДаннымПоля, ДанныеПечати);
	
	Если ЗначениеЗаполнено(ПутьКДаннымТабличнойЧасти) Тогда
		Возврат Сред(ПутьКДаннымПоля, СтрДлина(ПутьКДаннымТабличнойЧасти) + 2);
	КонецЕсли;
	
	Возврат ПутьКДаннымПоля;
	
КонецФункции

Функция ПутьКДаннымТабличнойЧасти(ПутьКДаннымПоля, ДанныеПечати)
	
	ПутьКДаннымРодителя = ПутьКДаннымРодителя(ПутьКДаннымПоля);
	
	Пока ЗначениеЗаполнено(ПутьКДаннымРодителя) Цикл
		Если ДанныеПечати["ИменаТабличныхЧастейОбъекта"].Найти(ПутьКДаннымРодителя) <> Неопределено Тогда
			Возврат ПутьКДаннымРодителя;
		КонецЕсли;
		
		ПутьКДаннымРодителя = ПутьКДаннымРодителя(ПутьКДаннымРодителя);
	КонецЦикла;
	
	Возврат "";
	
КонецФункции

Функция ЭтоПолеТабличнойЧасти(ПутьКДаннымПоля, ДанныеПечати)
	
	ПутьКДаннымРодителя = ПутьКДаннымРодителя(ПутьКДаннымПоля);
	
	Пока ЗначениеЗаполнено(ПутьКДаннымРодителя) Цикл
		ЭтоПолеТабличнойЧасти = ДанныеПечати["ИменаТабличныхЧастейОбъекта"].Найти(ПутьКДаннымРодителя) <> Неопределено;
		Если ЭтоПолеТабличнойЧасти Тогда
			Возврат Истина;
		КонецЕсли;
		
		ПутьКДаннымРодителя = ПутьКДаннымРодителя(ПутьКДаннымРодителя);
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

Функция ИмяПоля(ПутьКДаннымПоля)
	
	ЧастиПути = СтрРазделить(ПутьКДаннымПоля, ".", Истина);
	Возврат ЧастиПути[ЧастиПути.ВГраница()];

КонецФункции

Функция ПутьКДаннымРодителя(ПутьКДаннымПоля)
	
	ЧастиПути = СтрРазделить(ПутьКДаннымПоля, ".", Истина);
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	
	Возврат СтрСоединить(ЧастиПути, ".");
	
КонецФункции

Функция КоллекцияПараметровПолученияДанныхИсточников()

	Параметры = Новый Структура;
	Параметры.Вставить("ИсточникиДанных");
	Параметры.Вставить("ПоляСхемы");
	Параметры.Вставить("КодЯзыка");
	Параметры.Вставить("СхемаКомпоновкиДанных");
	Параметры.Вставить("ИдентификаторСхемыКомпоновкиДанных");
	Параметры.Вставить("ОписанияИсточниковДанных");
	Параметры.Вставить("ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных");
	
	Возврат Параметры;
	
КонецФункции

Функция ДанныеИсточников(Параметры)

	Если Не ЗначениеЗаполнено(Параметры.ИсточникиДанных) Тогда
		Возврат Новый Соответствие();
	КонецЕсли;

	РезультатКомпоновки = СкомпоноватьДанные(Параметры);
	
	Таблицы = РезультатКомпоновки.Таблицы;
	ДанныеРасшифровки = РезультатКомпоновки.ДанныеРасшифровки;
	
	Результат = Новый Соответствие;
	Результат.Вставить("ИменаТабличныхЧастейОбъекта", Таблицы);
	
	Для Каждого Ссылка Из Параметры.ИсточникиДанных Цикл
		Результат[Ссылка] = Новый Соответствие();
		Для Каждого Таблица Из Таблицы Цикл
			Результат[Ссылка][Таблица] = Новый Соответствие();
		КонецЦикла;
		Для Каждого Поле Из Параметры.ПоляСхемы Цикл
			ЧастиИмени = СтрРазделить(Поле, ".", Истина);
			Если Таблицы.Найти(ЧастиИмени[0]) = Неопределено Тогда
				Результат[Ссылка][Поле] = Неопределено;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	ПериодическиеЗначения = Новый Соответствие;
	
	Для Каждого ЭлементРасшифровки Из ДанныеРасшифровки.Элементы Цикл
		
		Если ТипЗнч(ЭлементРасшифровки) = Тип("ЭлементРасшифровкиКомпоновкиДанныхГруппировка") Тогда
			Продолжить;
		КонецЕсли;
		
		ПараметрыРасшифровки = ПараметрыРасшифровки(ЭлементРасшифровки);
		
		Если Не ЗначениеЗаполнено(ПараметрыРасшифровки.ИмяПоляРасшифровки) Тогда
			Продолжить;
		КонецЕсли;
		
		ИмяПоля = ПараметрыРасшифровки.ИмяПоляРасшифровки;
		ЧастиСтроки = СтрРазделить(ПараметрыРасшифровки.ИмяПоляРасшифровки, ".");
		ИмяТаблицы = ЧастиСтроки[0];
		Если ЧастиСтроки.Количество() = 2 Тогда
			ИмяПоля = ЧастиСтроки[1];
		КонецЕсли;
		
		Ссылка = ПараметрыРасшифровки.СписокПолей["Ссылка"];
		ДанныеПечати = Результат[Ссылка];
		Если ДанныеПечати = Неопределено Тогда
			Результат.Вставить(Ссылка, Новый Соответствие);
			ДанныеПечати = Результат[Ссылка];
		КонецЕсли;
		
		Если ПериодическиеЗначения[Ссылка] = Неопределено Тогда
			ПериодическиеЗначения[Ссылка] = Новый Соответствие;
		КонецЕсли;
		
		Если Таблицы.Найти(ИмяТаблицы) <> Неопределено Тогда
			Таблица = ДанныеПечати[ИмяТаблицы];
			Если Таблица = Неопределено Тогда
				ДанныеПечати.Вставить(ИмяТаблицы, Новый Соответствие);
				Таблица = ДанныеПечати[ИмяТаблицы];
			КонецЕсли;
			
			НомерСтрокиТаблицы = ПараметрыРасшифровки.СписокПолей[ИмяТаблицы + ".НомерСтроки"];
			СтрокаТаблицы = Таблица[НомерСтрокиТаблицы];
			Если СтрокаТаблицы = Неопределено Тогда
				Таблица.Вставить(НомерСтрокиТаблицы, Новый Соответствие);
				СтрокаТаблицы = Таблица[НомерСтрокиТаблицы];
			КонецЕсли;
			
			СтрокаТаблицы.Вставить(ИмяПоля, ПараметрыРасшифровки.СписокПолей[ПараметрыРасшифровки.ИмяПоляРасшифровки]);
		Иначе
			ИмяПоля = ПараметрыРасшифровки.ИмяПоляРасшифровки;
			Если ПараметрыРасшифровки.СписокПолей["Период"] <> Неопределено И ИмяПоля <> "Ссылка" И ИмяПоля <> "Период" Тогда
				Если ПериодическиеЗначения[Ссылка][ИмяПоля] = Неопределено Тогда
					ТаблицаЗначений = Новый ТаблицаЗначений;
					ТаблицаЗначений.Колонки.Добавить("Период", Новый ОписаниеТипов("Дата"));
					ТаблицаЗначений.Колонки.Добавить("Значение");
					ПериодическиеЗначения[Ссылка][ИмяПоля] = ТаблицаЗначений;
				КонецЕсли;
				СтрокаТаблицы = ПериодическиеЗначения[Ссылка][ИмяПоля].Добавить();
				СтрокаТаблицы.Период = ПараметрыРасшифровки.СписокПолей["Период"];
				СтрокаТаблицы.Значение = ПараметрыРасшифровки.СписокПолей[ИмяПоля];
			КонецЕсли;
			
			Если ИмяПоля = "Номер" И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрефиксацияОбъектов") Тогда
				МодульПрефиксацияОбъектовКлиентСервер = ОбщегоНазначения.ОбщийМодуль("ПрефиксацияОбъектовКлиентСервер");
				Значение = МодульПрефиксацияОбъектовКлиентСервер.НомерНаПечать(ПараметрыРасшифровки.СписокПолей[ИмяПоля]);
				ДанныеПечати.Вставить(ИмяПоля, Значение);
			Иначе			
				ДанныеПечати.Вставить(ИмяПоля, ПараметрыРасшифровки.СписокПолей[ИмяПоля]);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	ЕстьПериодическиеЗначения = Ложь;
	Для Каждого Элемент Из ПериодическиеЗначения Цикл
		Если ЗначениеЗаполнено(Элемент.Значение) Тогда
			ЕстьПериодическиеЗначения = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если Параметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных Или Не ЕстьПериодическиеЗначения Тогда
		Возврат Результат;
	КонецЕсли;

	ВладельцыИсточников = Параметры.ОписанияИсточниковДанных.ВыгрузитьКолонку("Владелец");
	
	ТипыСсылок = Новый Соответствие;
	Для Каждого Ссылка Из ВладельцыИсточников Цикл
		Если Ссылка = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Тип = ТипЗнч(Ссылка);
		Если ТипыСсылок[Тип] = Неопределено Тогда
			ТипыСсылок[Тип] = Новый Массив;
		КонецЕсли;
		ТипыСсылок[Тип].Добавить(Ссылка);
	КонецЦикла;
	
	Если Не ЗначениеЗаполнено(ТипыСсылок) Тогда
		Возврат Результат;
	КонецЕсли;

	ЗначенияПериода = Новый Соответствие;
	Для Каждого ТипСсылок Из ТипыСсылок Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипСсылок.Ключ);
		Если ОбъектМетаданных <> Неопределено И ОбщегоНазначения.ЭтоДокумент(ОбъектМетаданных) Тогда
			ЗначенияДаты = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(ТипСсылок.Значение, "Дата");
			Для Каждого Ссылка Из ТипСсылок.Значение Цикл
				ЗначенияПериода.Вставить(Ссылка, ЗначенияДаты[Ссылка]);
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	
	Параметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = Истина;

	Для Каждого ОписаниеИсточникаДанных Из Параметры.ОписанияИсточниковДанных Цикл
		Ссылка = ОписаниеИсточникаДанных.Значение;
		
		ДанныеПечати = Результат[Ссылка];
		Если ДанныеПечати = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Владелец = ОписаниеИсточникаДанных.Владелец;
		Результат[Владелец] = Новый Соответствие;
		Для Каждого Поле Из ДанныеПечати Цикл
			Результат[Владелец][Поле.Ключ] = Поле.Значение;
			Период = ЗначенияПериода[Владелец];
			Если Период <> Неопределено И ПериодическиеЗначения[Ссылка] <> Неопределено И ПериодическиеЗначения[Ссылка][Поле.Ключ] <> Неопределено Тогда
				Результат[Владелец][Поле.Ключ] = Неопределено;
				Для Каждого ОписаниеЗначения Из ПериодическиеЗначения[Ссылка][Поле.Ключ] Цикл
					Если ОписаниеЗначения.Период <= Период Тогда
						Результат[Владелец][Поле.Ключ] = ОписаниеЗначения.Значение;
						Прервать;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция НайтиПолеВИерархии(Знач Поле, ИерархияПолей)
	
	Результат= ИерархияПолей[Поле];
	Если Результат = Неопределено Тогда
		Для Каждого Элемент Из ИерархияПолей Цикл
			Результат = НайтиПолеВИерархии(Поле, Элемент.Значение);
			Если Результат <> Неопределено Тогда
				Возврат Результат;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  Параметры - см. КоллекцияПараметровПолученияДанныхИсточников
//
Функция СкомпоноватьДанные(Параметры)
	
	Объекты = Параметры.ИсточникиДанных;
	ПоляМакета = ОбщегоНазначения.СкопироватьРекурсивно(Параметры.ПоляСхемы);
	КодЯзыка = Параметры.КодЯзыка;
	СхемаКомпоновкиДанных = Параметры.СхемаКомпоновкиДанных;
	ИдентификаторСхемыКомпоновкиДанных = Параметры.ИдентификаторСхемыКомпоновкиДанных;
	ОписанияИсточниковДанных = Параметры.ОписанияИсточниковДанных;
	ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = Параметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных;
	
	ВнешниеНаборыДанных = Новый Структура;
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ОписанияИсточниковДанных", ОписанияИсточниковДанных);
	ДополнительныеПараметры.Вставить("ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных", ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных);
	
	ТекстЗаголовка = ИдентификаторСхемыКомпоновкиДанных;
	
	ТребуетсяПодготовкаВнешнегоНабораДанных = Ложь;
	Для Каждого НаборДанных Из СхемаКомпоновкиДанных.НаборыДанных Цикл
		Если ТипЗнч(НаборДанных) = Тип("НаборДанныхОбъектСхемыКомпоновкиДанных") Тогда
			ТребуетсяПодготовкаВнешнегоНабораДанных = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если ТребуетсяПодготовкаВнешнегоНабораДанных Тогда
		Если Метаданные.НайтиПоПолномуИмени(ИдентификаторСхемыКомпоновкиДанных) = Неопределено Тогда
			ПриПодготовкеДанныхПечати(Объекты, ВнешниеНаборыДанных, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка, ДополнительныеПараметры);
		Иначе
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИдентификаторСхемыКомпоновкиДанных);
			МенеджерОбъекта.ПриПодготовкеДанныхПечати(Объекты, ВнешниеНаборыДанных, КодЯзыка, ДополнительныеПараметры);
		КонецЕсли;
	КонецЕсли;
	
	ОписанияИсточниковДанных = ДополнительныеПараметры.ОписанияИсточниковДанных;
	ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = ДополнительныеПараметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных;
	
	Если ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных Тогда
		Объекты = ОписанияИсточниковДанных.ВыгрузитьКолонку("Владелец");
		Объекты = ОбщегоНазначенияКлиентСервер.СвернутьМассив(Объекты);
	КонецЕсли;
		
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	АдресСхемы = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных);
	КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы));
	КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
	
	НастройкиКомпоновщика = КомпоновщикНастроек.Настройки;
	
	ВыводРеквизитов = НастройкиКомпоновщика.ПараметрыВывода.Элементы.Найти("РасположениеРеквизитов");
	ВыводРеквизитов.Значение = РасположениеРеквизитовКомпоновкиДанных.Отдельно;
	ВыводРеквизитов.Использование = Истина;
	
	РасположениеИтогов = НастройкиКомпоновщика.ПараметрыВывода.Элементы.Найти("РасположениеИтогов");
	РасположениеИтогов.Значение = РасположениеИтоговКомпоновкиДанных.Нет;
	РасположениеИтогов.Использование = Истина;

	ВыводитьОтбор = НастройкиКомпоновщика.ПараметрыВывода.Элементы.Найти("ВыводитьОтбор");
	ВыводитьОтбор.Значение = ТипВыводаТекстаКомпоновкиДанных.НеВыводить;
	ВыводитьОтбор.Использование = Истина;

	Заголовок = НастройкиКомпоновщика.ПараметрыВывода.Элементы.Найти("Заголовок");
	Заголовок.Значение = ТекстЗаголовка;
	Заголовок.Использование = Истина;
	
	Таблицы = Новый Массив;
	Для Каждого Поле Из НастройкиКомпоновщика.ДоступныеПоляВыбора.Элементы Цикл
		Если Поле.Таблица Тогда
			ИмяТаблицы = Строка(Поле.Поле);
			Таблицы.Добавить(ИмяТаблицы);
		КонецЕсли;
	КонецЦикла;
	
	НастройкиКомпоновщика.Структура.Очистить();
	
	КлючевоеПоле = Неопределено;
	Для Каждого ИмяПоля Из СтрРазделить("Ссылка", ",") Цикл
		КлючевоеПоле = Новый ПолеКомпоновкиДанных(ИмяПоля);
		Если НастройкиКомпоновщика.ДоступныеПоляГруппировок.НайтиПоле(КлючевоеПоле) <> Неопределено Тогда
			Прервать;
		Иначе
			КлючевоеПоле = Неопределено;
		КонецЕсли;
	КонецЦикла;
	
	Если КлючевоеПоле = Неопределено Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр(
			"ru = 'Не найдено ключевое поле ""%1"" в списке полей схемы компоновки данных печати ""%2"".
			|См. описание параметра ""%3"" в процедуре ""%4"".'"),
			"Ссылка",
			ИдентификаторСхемыКомпоновкиДанных,
			"ИсточникиДанныхПечати",
			"УправлениеПечатьюПереопределяемый.ПриОпределенииИсточниковДанныхПечати");
	КонецЕсли;
	
	Группировка = НастройкиКомпоновщика.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));

	Поле = Группировка.ПоляГруппировки.Элементы.Добавить(Тип("ПолеГруппировкиКомпоновкиДанных"));
	Поле.Поле = КлючевоеПоле;
	Поле.Использование = Истина;
	
	Группировка.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
	
	ТаблицаКомпоновкиДанных = Группировка.Структура.Добавить(Тип("ТаблицаКомпоновкиДанных"));
	
	Шапка = ТаблицаКомпоновкиДанных.Строки.Добавить();
	Шапка.ПоляГруппировки.Элементы.Добавить(Тип("АвтоПолеГруппировкиКомпоновкиДанных"));

	Если ПоляМакета.Найти("Период") = Неопределено Тогда
		ПоляМакета.Добавить("Период");
	КонецЕсли;
	
	Для Каждого ПутьКДанным Из ПоляМакета Цикл
		Если Таблицы.Найти(СтрРазделить(ПутьКДанным, ".", Истина)[0]) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		ДоступноеПоле = НастройкиКомпоновщика.Выбор.ДоступныеПоляВыбора.НайтиПоле(Новый ПолеКомпоновкиДанных(ПутьКДанным));
		Если ДоступноеПоле = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если ДоступноеПоле.Папка Тогда
			Поле = Шапка.Выбор.Элементы.Добавить(Тип("ГруппаВыбранныхПолейКомпоновкиДанных"));
		Иначе
			Поле = Шапка.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
		КонецЕсли;
		Поле.Поле = Новый ПолеКомпоновкиДанных(ПутьКДанным);
		Поле.Использование = Истина;
	КонецЦикла;
	
	Для Каждого ИмяТабличнойЧасти Из Таблицы Цикл
		ТаблицаКомпоновкиДанных = Группировка.Структура.Добавить(Тип("ТаблицаКомпоновкиДанных"));
		
		ГруппировкаПоНомеруСтроки = ТаблицаКомпоновкиДанных.Строки.Добавить();
		ГруппировкаПоНомеруСтроки.ПоляГруппировки.Элементы.Добавить(Тип("ПолеГруппировкиКомпоновкиДанных"));

		Поле = ГруппировкаПоНомеруСтроки.ПоляГруппировки.Элементы.Добавить(Тип("ПолеГруппировкиКомпоновкиДанных"));
		Поле.Поле = Новый ПолеКомпоновкиДанных(ИмяТабличнойЧасти + ".НомерСтроки");
		Поле.Использование = Истина;
		
		ДанныеТабличнойЧасти = ГруппировкаПоНомеруСтроки.Структура.Добавить();
		ДанныеТабличнойЧасти.ПоляГруппировки.Элементы.Добавить(Тип("АвтоПолеГруппировкиКомпоновкиДанных"));
		
		Для Каждого ПутьКДанным Из ПоляМакета Цикл
			Если СтрРазделить(ПутьКДанным, ".", Истина)[0] <> ИмяТабличнойЧасти Тогда
				Продолжить;
			КонецЕсли;
			
			ДоступноеПоле = НастройкиКомпоновщика.Выбор.ДоступныеПоляВыбора.НайтиПоле(Новый ПолеКомпоновкиДанных(ПутьКДанным));
			Если ДоступноеПоле = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Если ДоступноеПоле.Папка Тогда
				Поле = ДанныеТабличнойЧасти.Выбор.Элементы.Добавить(Тип("ГруппаВыбранныхПолейКомпоновкиДанных"));
			Иначе
				Поле = ДанныеТабличнойЧасти.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
			КонецЕсли;
			Поле.Поле = Новый ПолеКомпоновкиДанных(ПутьКДанным);
			Поле.Использование = Истина;
		КонецЦикла;
	КонецЦикла;
	
	Группировка.Структура.Добавить(Тип("ТаблицаКомпоновкиДанных"));
	
	ЭлементОтбора = НастройкиКомпоновщика.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение = КлючевоеПоле;
	ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
	ЭлементОтбора.ПравоеЗначение = Новый СписокЗначений;
	ЭлементОтбора.ПравоеЗначение.ЗагрузитьЗначения(Объекты);
	
	ДокументРезультат = Новый ТабличныйДокумент;
	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
	ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
	
	МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновщика, ДанныеРасшифровки);
	
	ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
	ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
	
	ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
	ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
	ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);	
	
	Параметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных;
	
	Результат = Новый Структура;
	Результат.Вставить("ДанныеРасшифровки", ДанныеРасшифровки);
	Результат.Вставить("Таблицы", Таблицы);
	
	Возврат	Результат;
	
КонецФункции

Функция МакетСуществует(ПутьКМакету)
	
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	
	Идентификатор = ЧастиПути[ЧастиПути.ВГраница()];
	Если СтрНачинаетсяС(Идентификатор, "ПФ_") Тогда
		Идентификатор = Сред(Идентификатор, 4);
		Если СтроковыеФункцииКлиентСервер.ЭтоУникальныйИдентификатор(Идентификатор) Тогда
			МакетСуществует = Справочники.МакетыПечатныхФорм.МакетСуществует(Новый УникальныйИдентификатор(Идентификатор));
			Если МакетСуществует Тогда
				Возврат Истина;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ИмяМакета = ЧастиПути[ЧастиПути.ВГраница()];
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	
	ЭтоОбщийМакет = СтрРазделить(ИмяОбъекта, ".").Количество() = 1;
	КоллекцияМакетов = Метаданные.ОбщиеМакеты;
	
	Если Не ЭтоОбщийМакет Тогда
		ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта);
		Если ОбъектМетаданных = Неопределено Тогда
			Возврат Ложь;
		КонецЕсли;
		КоллекцияМакетов = ОбъектМетаданных.Макеты;
	КонецЕсли;
	
	Возврат КоллекцияМакетов.Найти(ИмяМакета) <> Неопределено;
	
КонецФункции

// Параметры:
//  ДанныеРасшифровки - ДанныеРасшифровкиКомпоновкиДанных
//  Расшифровка - ИдентификаторРасшифровкиКомпоновкиДанных - элемент расшифровки.
//
// Возвращаемое значение:
//  Структура:
//   * ИмяПоляРасшифровки - Строка
//   * СписокПолей - Соответствие из КлючИЗначение:
//    ** Ключ - Строка
//    ** Значение - Произвольный
//
Функция ПараметрыРасшифровки(ЭлементРасшифровки)
	
	СписокПолей = Новый Соответствие;
	ЗаполнитьСписокПолей(СписокПолей, ЭлементРасшифровки);
	
	ИмяПоляРасшифровки = "";
	Для Каждого ЗначениеПоля Из ЭлементРасшифровки.ПолучитьПоля() Цикл
		ИмяПоляРасшифровки = ЗначениеПоля.Поле;
		Прервать;
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяПоляРасшифровки", ИмяПоляРасшифровки);
	Результат.Вставить("СписокПолей", СписокПолей);
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//   СписокПолей - Соответствие из КлючИЗначение:
//    ** Ключ - Строка
//    ** Значение - Произвольный
//   ЭлементРасшифровки - ЭлементРасшифровкиКомпоновкиДанныхПоля
//                      - ЭлементРасшифровкиКомпоновкиДанныхГруппировка
//
Процедура ЗаполнитьСписокПолей(СписокПолей, ЭлементРасшифровки)
	
	Если ТипЗнч(ЭлементРасшифровки) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
		Для Каждого ЗначениеПоля Из ЭлементРасшифровки.ПолучитьПоля() Цикл
			Если СписокПолей[ЗначениеПоля.Поле] = Неопределено Тогда
				СписокПолей.Вставить(ЗначениеПоля.Поле, ЗначениеПоля.Значение);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
		
	Для Каждого Родитель Из ЭлементРасшифровки.ПолучитьРодителей() Цикл
		ЗаполнитьСписокПолей(СписокПолей, Родитель);
	КонецЦикла;
	
КонецПроцедуры

Функция ЗначенияПараметров(Параметры, ДанныеПечати, НастройкиФорматаПолей, КодЯзыка)
	
	Результат = Новый Соответствие;

	Для Каждого Параметр Из Параметры Цикл
		Значение = ВычислитьВыражение(Параметр, ДанныеПечати, НастройкиФорматаПолей, КодЯзыка);
		Результат.Вставить(Параметр, Значение);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ВычислитьВыражение(Знач ИсходноеВыражение, ДанныеПечати, НастройкиФорматаПолей, КодЯзыка, ПрименятьФорматирование = Неопределено)
	
	Выражение = ИсходноеВыражение;
	Выражение = Сред(Выражение, 2, СтрДлина(Выражение) - 2);
	
	ЭлементыФормулы = КонструкторФормулСлужебный.ЭлементыФормулы(Выражение);
	ВыделитьИмяКолонкиТабличнойЧасти(Выражение, ЭлементыФормулы);
	
	Параметры = Новый Массив;
	
	Если ПрименятьФорматирование = Неопределено Тогда
		ПрименятьФорматирование = Ложь;
		
		Если ЭлементыФормулы.ОперандыИФункции.Количество() = 1 Тогда
			Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
				ЭтоФункция = ОписаниеЭлемента.Значение;
				Если ЭтоФункция Тогда
					Прервать;
				КонецЕсли;
				Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
				ПрименятьФорматирование = Операнд = Выражение;
				Прервать;
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
		Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
		ЭтоФункция = ОписаниеЭлемента.Значение;
		КоллекцияДанных = ДанныеПечати;
		
		Если Не ЭтоФункция Тогда
			Если СтрНайти("И,ИЛИ,НЕ,ИСТИНА,ЛОЖЬ", ВРег(Операнд)) Тогда
				Продолжить;
			КонецЕсли;
			
			Значение = КоллекцияДанных[ОчиститьКвадратныеСкобки(Операнд) + "." + СтрРазделить(КодЯзыка, "_")[0]];
			Если Не ЗначениеЗаполнено(Значение) Тогда
				Значение = КоллекцияДанных[ОчиститьКвадратныеСкобки(Операнд)];
			КонецЕсли;
			
			Формат = "";
			Если ПрименятьФорматирование Тогда
				Формат = НастройкиФорматаПолей[Операнд];
			КонецЕсли;

			Если ЗначениеЗаполнено(Формат) И ЭлементыФормулы.ОперандыИФункции.Количество() = 1 Тогда
				Если ЗначениеЗаполнено(КодЯзыка) Тогда
					Формат = СтрШаблон("Л=%1;", КодЯзыка) + Формат;
				КонецЕсли;
				Значение = Формат(Значение, Формат);
			КонецЕсли;
			
			Параметры.Добавить(Значение);
			ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ] = "Параметры[" + Параметры.ВГраница() + "]";
		КонецЕсли;
	КонецЦикла;
	
	Выражение = СтрСоединить(ЭлементыФормулы.ВсеЭлементы);
	Выражение = СтрЗаменить(Выражение, ИмяМодуляПечати() + РазделительКоманды(), ИмяМодуляПечати() + ".");
	
	Попытка
		Результат = ОбщегоНазначения.ВычислитьВБезопасномРежиме(Выражение, Параметры);
	Исключение
		ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		ОбщегоНазначения.СообщитьПользователю(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Выражение ""%1"" содержит ошибки:
			|%2'"), ИсходноеВыражение, ТекстОшибки));
		Результат = "";
	КонецПопытки;
	
	Возврат Результат;
	
КонецФункции

Процедура ВыделитьИмяКолонкиТабличнойЧасти(Выражение, ЭлементыФормулы)
	
	ФункцииСРазделениемПараметров = ФункцииСРазделениемПараметров();	
	
	ФункцияНайдена = Ложь;
	Для Каждого ИмяФункции Из ФункцииСРазделениемПараметров Цикл
		Если СтрНайти(Выражение, ИмяФункции) Тогда
			ФункцияНайдена = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если ФункцияНайдена Тогда
		Результат = Новый Массив;
		ВсеЭлементыВыражения = ЭлементыФормулы.ВсеЭлементы;
		Для Индекс = 0 По ВсеЭлементыВыражения.ВГраница() Цикл
			Элемент = ВсеЭлементыВыражения[Индекс];
			Результат.Добавить(Элемент);
			Если СтрНачинаетсяС(Элемент, ИмяМодуляПечати() + РазделительКоманды()) Тогда
				Результат.Добавить(ВсеЭлементыВыражения[Индекс+1]); 
				МассивИменПараметра = СтрРазделить(ВсеЭлементыВыражения[Индекс+2], ".", Ложь);
				Результат.Добавить(МассивИменПараметра[0]);
				Результат.Добавить(",");
				Если МассивИменПараметра.Количество() = 2 Тогда
					Результат.Добавить("""");
					ИмяКолонки = МассивИменПараметра[1];
					Для Позиция = 1 По СтрДлина(ИмяКолонки) Цикл
						Результат.Добавить(Сред(ИмяКолонки, Позиция, 1));
					КонецЦикла;
					Результат.Добавить("""");
				КонецЕсли;
				Результат.Добавить(ВсеЭлементыВыражения[Индекс+3]);
				Индекс = Индекс + 3;
			КонецЕсли;
		КонецЦикла;
		ЭлементыФормулы.ВсеЭлементы = Результат;
	КонецЕсли;
	
КонецПроцедуры

Функция ФункцииСРазделениемПараметров()
	
	ИмяМодуляПечатиСРазделителем = ИмяМодуляПечати() + РазделительКоманды();
	
	ФункцииСРазделениемПараметров = Новый Массив();	
	ФункцииСРазделениемПараметров.Добавить(ИмяМодуляПечатиСРазделителем + "СуммаПоКолонке");
	ФункцииСРазделениемПараметров.Добавить(ИмяМодуляПечатиСРазделителем + "КоличествоСтрок");
	ФункцииСРазделениемПараметров.Добавить(ИмяМодуляПечатиСРазделителем + "Максимум");
	ФункцииСРазделениемПараметров.Добавить(ИмяМодуляПечатиСРазделителем + "Минимум");
	ФункцииСРазделениемПараметров.Добавить(ИмяМодуляПечатиСРазделителем + "Среднее");
	
	Возврат ФункцииСРазделениемПараметров;
	
КонецФункции

Функция ИмяМодуляПечати()
	Возврат Метаданные.ОбщиеМодули.УправлениеПечатью.Имя;
КонецФункции

Функция РазделительКоманды()
	Возврат "_";
КонецФункции

Функция ОчиститьКвадратныеСкобки(Строка)
	
	Если СтрНачинаетсяС(Строка, "[") И СтрЗаканчиваетсяНа(Строка, "]") Тогда
		Возврат Сред(Строка, 2, СтрДлина(Строка) - 2);
	КонецЕсли;
	
	Возврат Строка;
	
КонецФункции

Функция ОбластиМакета(Макет, ДанныеПечати)
	
	Таблицы = ДанныеПечати["ИменаТабличныхЧастейОбъекта"];
	ВсеОбласти = Новый СписокЗначений;
	ОбластиТаблиц = Новый Соответствие;
	
	ОбластиСУсловиями = Новый Соответствие;
	Для Каждого Область Из Макет.Области Цикл
		Если ТипЗнч(Область) = Тип("ОбластьЯчеекТабличногоДокумента") И Область.ТипОбласти = ТипОбластиЯчеекТабличногоДокумента.Строки Тогда
			ОбластиСУсловиями.Вставить(Область.Верх, Область);
		КонецЕсли;
	КонецЦикла;	
	
	ОбластиДляОбработки = Новый Массив;
	
	НачалоОбласти = 1;
	Для НомерСтроки = 1 По Макет.ВысотаТаблицы Цикл
		Если ОбластиСУсловиями[НомерСтроки] <> Неопределено Тогда
			Если НачалоОбласти < НомерСтроки Тогда
				Область = Макет.Область(НачалоОбласти, , НомерСтроки-1);
				ОбластиДляОбработки.Добавить(Область);
			КонецЕсли;
			ОбластиДляОбработки.Добавить(ОбластиСУсловиями[НомерСтроки]);
			НомерСтроки = ОбластиСУсловиями[НомерСтроки].Низ;
			НачалоОбласти = НомерСтроки + 1;
		КонецЕсли;
	КонецЦикла;
	
	Если Макет.ВысотаТаблицы >= НачалоОбласти Тогда
		Область = Макет.Область(НачалоОбласти, , Макет.ВысотаТаблицы);
		ОбластиДляОбработки.Добавить(Область);
	КонецЕсли;
	
	Для Каждого Область Из ОбластиДляОбработки Цикл // ОбластьЯчеекТабличногоДокумента
		ОписаниеОбластей = РазделитьНаОбласти(Макет, Область, Таблицы);
		ОбщегоНазначенияКлиентСервер.ДополнитьСоответствие(ОбластиТаблиц, ОписаниеОбластей.ОбластиТаблиц);
		УсловиеВывода = "";
		Если Макет.Области.Найти(Область.Имя) <> Неопределено Тогда
			УсловиеВывода = Область.ПараметрРасшифровки;
		КонецЕсли;
		Для Каждого ИдентификаторОбласти Из ОписаниеОбластей.ВсеОбласти Цикл
			ВсеОбласти.Добавить(ИдентификаторОбласти, УсловиеВывода);
		КонецЦикла;
	КонецЦикла;

	Результат = Новый Структура;
	Результат.Вставить("ВсеОбласти", ВсеОбласти);
	Результат.Вставить("ОбластиТаблиц", ОбластиТаблиц);
	
	Возврат Результат;
	
КонецФункции

Функция РазделитьНаОбласти(Макет, Область, Таблицы)
	
	ВсеОбласти = Новый Массив;
	ОбластиТаблиц = Новый Соответствие;
	
	НачалоОбласти = Область.Верх;
	ТекущаяТаблица = "";
	ПредыдущаяТаблица = "";
	
	Для НомерСтроки = Область.Верх По Область.Низ Цикл
		Верх = НомерСтроки;
		Низ = НомерСтроки;
		
		Для НомерКолонки = 1 По Макет.ШиринаТаблицы Цикл
			ОбластьЯчейки = Макет.Область(НомерСтроки, НомерКолонки);
			Низ = Макс(Низ, ОбластьЯчейки.Низ);
		КонецЦикла;
		
		НомерСтроки = Низ;
		ОбластьСтроки = Макет.Область(Верх, , Низ);
		ТекущаяТаблица = ИмяТаблицыВОбластиМакета(Макет, ОбластьСтроки, Таблицы);
	
		Если ПредыдущаяТаблица <> ТекущаяТаблица И Верх > НачалоОбласти Тогда
			ИдентификаторОбласти = "R" + XMLСтрока(НачалоОбласти) + ":R" + XMLСтрока(Верх - 1);
			ВсеОбласти.Добавить(ИдентификаторОбласти);
			
			Если ЗначениеЗаполнено(ПредыдущаяТаблица) Тогда
				ОбластиТаблиц.Вставить(ИдентификаторОбласти, ПредыдущаяТаблица);
			КонецЕсли;
			
			НачалоОбласти = Верх;
		КонецЕсли;

		ПредыдущаяТаблица = ТекущаяТаблица;
	КонецЦикла;
	
	ИдентификаторОбласти = "R" + XMLСтрока(НачалоОбласти) + ":R" + Область.Низ;

	Если ЗначениеЗаполнено(ТекущаяТаблица) Тогда
		ОбластиТаблиц.Вставить(ИдентификаторОбласти, ПредыдущаяТаблица);
	КонецЕсли;
	ВсеОбласти.Добавить(ИдентификаторОбласти);
	
	Результат = Новый Структура;
	Результат.Вставить("ВсеОбласти", ВсеОбласти);
	Результат.Вставить("ОбластиТаблиц", ОбластиТаблиц);
	
	Возврат Результат;
	
КонецФункции

Функция ИмяТаблицыВОбластиМакета(Макет, Область, Таблицы)
	
	ОбработанныеЯчейки = Новый Соответствие;
	
	ИмяТаблицы = "";
	Для НомерСтроки = Область.Верх По Область.Низ Цикл
		Для НомерСтолбца = 1 По Макет.ШиринаТаблицы Цикл
			ОбластьЯчейки = Макет.Область(НомерСтроки, НомерСтолбца, НомерСтроки, НомерСтолбца);
			
			ИдентификаторОбласти = ИдентификаторОбласти(ОбластьЯчейки);
			Если ОбработанныеЯчейки[ИдентификаторОбласти] <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ОбработанныеЯчейки[ИдентификаторОбласти] = Истина;

			Для Каждого Таблица Из Таблицы Цикл
				СтрокаПоиска = "[" + Таблица + ".";
				Если СтрНайти(ОбластьЯчейки.Текст, СтрокаПоиска) Тогда
					ИмяТаблицы = Таблица;
					Прервать;
				КонецЕсли;
			КонецЦикла;

			Если ЗначениеЗаполнено(ИмяТаблицы) Тогда
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
		Если ЗначениеЗаполнено(ИмяТаблицы) Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ИмяТаблицы;
	
КонецФункции

Функция ПоляМакета(Макет)

	Тексты = Новый Соответствие;
	
	ОбработанныеЯчейки = Новый Соответствие;
	Для НомерСтроки = 1 По Макет.ВысотаТаблицы Цикл
		Для НомерСтолбца = 1 По Макет.ШиринаТаблицы Цикл
			ОбластьЯчейки = Макет.Область(НомерСтроки, НомерСтолбца, НомерСтроки, НомерСтолбца);
			
			ИдентификаторОбласти = ИдентификаторОбласти(ОбластьЯчейки);
			Если ОбработанныеЯчейки[ИдентификаторОбласти] <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ОбработанныеЯчейки[ИдентификаторОбласти] = Истина;
			
			Если Не ЗначениеЗаполнено(ОбластьЯчейки.Текст) Тогда
				Продолжить;
			КонецЕсли;
			
			Тексты.Вставить(ОбластьЯчейки.Текст, Истина);
		КонецЦикла;
	КонецЦикла;
	
	Тексты.Вставить(Строка(Макет.ВерхнийКолонтитул.ТекстСлева), Истина);
	Тексты.Вставить(Строка(Макет.ВерхнийКолонтитул.ТекстВЦентре), Истина);
	Тексты.Вставить(Строка(Макет.ВерхнийКолонтитул.ТекстСправа), Истина);

	Тексты.Вставить(Строка(Макет.НижнийКолонтитул.ТекстСлева), Истина);
	Тексты.Вставить(Строка(Макет.НижнийКолонтитул.ТекстВЦентре), Истина);
	Тексты.Вставить(Строка(Макет.НижнийКолонтитул.ТекстСправа), Истина);
	
	Для Каждого Рисунок Из Макет.Рисунки Цикл
		Если Рисунок.ТипРисунка <> ТипРисункаТабличногоДокумента.Группа Тогда 
			Тексты.Вставить(Рисунок.ПараметрРасшифровки, Истина);
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого Область Из Макет.Области Цикл
		Если ТипЗнч(Область) = Тип("ОбластьЯчеекТабличногоДокумента")
			И Область.ТипОбласти = ТипОбластиЯчеекТабличногоДокумента.Строки Тогда
			УсловиеВывода = Область.ПараметрРасшифровки;
			Если ЗначениеЗаполнено(УсловиеВывода) Тогда
				Тексты.Вставить(Область.ПараметрРасшифровки);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Результат = Новый Массив;

	Для Каждого Элемент Из Тексты Цикл
		Текст = Элемент.Ключ;
		ПараметрыТекста = НайтиПараметрыВТексте(Текст);
		Для Каждого Выражение Из ПараметрыТекста Цикл
			Выражение = Сред(Выражение, 2, СтрДлина(Выражение) - 2);
			ЭлементыФормулы = КонструкторФормулСлужебный.ЭлементыФормулы(Выражение);
			Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
				ЭтоФункция = ОписаниеЭлемента.Значение;
				Если ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				
				Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
				Операнд = ОчиститьКвадратныеСкобки(Операнд);
				Если ЗначениеЗаполнено(Операнд) Тогда
					Результат.Добавить(Операнд);
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция КоличествоСтрок(Таблица, ИмяКолонки = Неопределено) Экспорт
	
	Если ТипЗнч(Таблица) = Тип("Соответствие") Тогда
		Возврат Таблица.Количество();
	КонецЕсли;
	
	ВызватьИсключение НСтр("ru = 'Неверно указана таблица'");
	
КонецФункции

Функция СуммаПоКолонке(Таблица, ИмяКолонки = Неопределено) Экспорт // АПК:299 - обработчик функций конструктора формул
	
	Если ТипЗнч(Таблица) = Тип("Соответствие") Тогда
		Значение = 0;
		ТипЧисло = Новый ОписаниеТипов("Число");
		Для Каждого СоответствиеСтроки Из Таблица Цикл
			СтрокаТаблицы = СоответствиеСтроки.Значение;
			Значение = Значение + ТипЧисло.ПривестиЗначение(СтрокаТаблицы[ИмяКолонки]);
		КонецЦикла;
		
		Возврат Значение;
	КонецЕсли;
	
	ВызватьИсключение НСтр("ru = 'Неверно указана колонка таблицы'");
	
КонецФункции

Функция МаксимумПоКолонке(Таблица, ИмяКолонки = Неопределено) Экспорт // АПК:299 - обработчик функций конструктора формул
	
	Если ТипЗнч(Таблица) = Тип("Соответствие") Тогда
		Значение = Неопределено;
		ТипЧисло = Новый ОписаниеТипов("Число");
		Для Каждого СоответствиеСтроки Из Таблица Цикл
			СтрокаТаблицы = СоответствиеСтроки.Значение;
			ЗначениеСтроки = ТипЧисло.ПривестиЗначение(СтрокаТаблицы[ИмяКолонки]);
			Значение = ?(Значение = Неопределено, ЗначениеСтроки, Значение);
			Значение = Макс(Значение, ЗначениеСтроки);
		КонецЦикла;
		
		Возврат Значение;
	КонецЕсли;
	
	ВызватьИсключение НСтр("ru = 'Неверно указана колонка таблицы'");
	
КонецФункции

Функция МинимумПоКолонке(Таблица, ИмяКолонки = Неопределено) Экспорт // АПК:299 - обработчик функций конструктора формул
	
	Если ТипЗнч(Таблица) = Тип("Соответствие") Тогда
		Значение = Неопределено;
		ТипЧисло = Новый ОписаниеТипов("Число");
		Для Каждого СоответствиеСтроки Из Таблица Цикл
			СтрокаТаблицы = СоответствиеСтроки.Значение;
			ЗначениеСтроки = ТипЧисло.ПривестиЗначение(СтрокаТаблицы[ИмяКолонки]);
			Значение = ?(Значение = Неопределено, ЗначениеСтроки, Значение);
			Значение = Мин(Значение, ЗначениеСтроки);
		КонецЦикла;
		
		Возврат Значение;
	КонецЕсли;
	
	ВызватьИсключение НСтр("ru = 'Неверно указана колонка таблицы'");
	
КонецФункции

Функция СреднееПоКолонке(Таблица, ИмяКолонки = Неопределено) Экспорт // АПК:299 - обработчик функций конструктора формул
	
	Если ТипЗнч(Таблица) = Тип("Соответствие") Тогда
		Значение = 0;
		ТипЧисло = Новый ОписаниеТипов("Число");
		Для Каждого СоответствиеСтроки Из Таблица Цикл
			СтрокаТаблицы = СоответствиеСтроки.Значение;
			Значение = Значение + ТипЧисло.ПривестиЗначение(СтрокаТаблицы[ИмяКолонки]);
		КонецЦикла;
		
		Возврат ?(Таблица.Количество(), Значение/Таблица.Количество(), 0);
	КонецЕсли;
	
	ВызватьИсключение НСтр("ru = 'Неверно указана колонка таблицы'");

КонецФункции

// Возвращаемое значение:
//   см. КонструкторФормулСлужебный.ОписаниеСписковПолей
//
Функция ОписаниеСписковПолей(ИсточникиДанныхПечати, Операторы = Неопределено, ИсточникДанных = Неопределено) Экспорт
	
	ОписаниеСписковПолей = КонструкторФормулСлужебный.ОписаниеСписковПолей();
	
	ИсточникиДоступныхПолей = КонструкторФормулСлужебный.КоллекцияИсточниковДоступныхПолей();
	Для Каждого Элемент Из ИсточникиДанныхПечати Цикл
		СхемаКомпоновкиДанных = Элемент.Значение;
		ИдентификаторСхемыКомпоновкиДанных = Элемент.Представление;
		ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить(); 
		ИсточникДоступныхПолей.КоллекцияПолей = КонструкторФормулСлужебный.КоллекцияПолей(СхемаКомпоновкиДанных);
		ИсточникДоступныхПолей.СхемаКомпоновкиДанных = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных);
		ИсточникДоступныхПолей.ИдентификаторСхемыКомпоновкиДанных = ИдентификаторСхемыКомпоновкиДанных;
		ИсточникДоступныхПолей.ИсточникДанных = ИсточникДанных;
	КонецЦикла;
	
	ОписаниеСпискаПолей = ОписаниеСписковПолей.Добавить();
	ОписаниеСпискаПолей.ИсточникиДоступныхПолей = ИсточникиДоступныхПолей;
	ОписаниеСпискаПолей.СкобкиПредставлений = Истина;
	ОписаниеСпискаПолей.ПриОпределенииИсточниковДоступныхПолей = "УправлениеПечатью";
	
	Если Операторы <> Неопределено Тогда
		ИсточникиДоступныхПолей = КонструкторФормулСлужебный.КоллекцияИсточниковДоступныхПолей();
		ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить(); 
		ИсточникДоступныхПолей.КоллекцияПолей = КонструкторФормулСлужебный.КоллекцияПолей(Операторы);
		
		ОписаниеСпискаПолей = ОписаниеСписковПолей.Добавить();
		ОписаниеСпискаПолей.ИсточникиДоступныхПолей = ИсточникиДоступныхПолей;
	КонецЕсли;
	
	Возврат ОписаниеСписковПолей;
	
КонецФункции

// Параметры:
//  ИмяИсточникаПолей - Строка
//  ИсточникиДоступныхПолей - ТаблицаЗначений
//  УникальныйИдентификаторФормы - УникальныйИдентификатор
//
Процедура ПриОпределенииИсточниковДоступныхПолей(ИмяИсточникаПолей, ТипИсточникаПолей, ИсточникиДоступныхПолей, УникальныйИдентификаторФормы) Экспорт
	
	СхемыКомпоновкиДанных = СхемыКомпоновкиДанныхИсточникаПолей(ИмяИсточникаПолей, , ТипИсточникаПолей);
	Для Каждого Элемент Из СхемыКомпоновкиДанных Цикл
		СхемаКомпоновкиДанных = Элемент.Значение;
		ИдентификаторСхемыКомпоновкиДанных = Элемент.Представление;
		ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить();
		ИсточникДоступныхПолей.ИсточникДанных = ИмяИсточникаПолей;
		ИсточникДоступныхПолей.СхемаКомпоновкиДанных = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных, УникальныйИдентификаторФормы);
		ИсточникДоступныхПолей.ИдентификаторСхемыКомпоновкиДанных = ИдентификаторСхемыКомпоновкиДанных;
		ИсточникДоступныхПолей.КоллекцияПолей = КонструкторФормул.КоллекцияПолей(СхемаКомпоновкиДанных);
		ИсточникДоступныхПолей.Замещать = Истина;
	КонецЦикла;
	
КонецПроцедуры

Функция СхемыКомпоновкиДанныхИсточникаПолей(ИмяИсточникаПолей, ДобавитьОбщиеРеквизиты = Ложь, ТипИсточникаПолей = Неопределено)
	
	ИсточникиПолей = Новый СписокЗначений;
	
	ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяИсточникаПолей);
	Если ОбъектМетаданных <> Неопределено Тогда
		Если ОбъектМетаданных.Макеты.Найти("ДанныеПечати") <> Неопределено Тогда
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя());
			СхемаКомпоновкиДанных = МенеджерОбъекта.ПолучитьМакет("ДанныеПечати");
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрефиксацияОбъектов") Тогда
				МодульПрефиксацияОбъектовСлужебный = ОбщегоНазначения.ОбщийМодуль("ПрефиксацияОбъектовСлужебный");
				МодульПрефиксацияОбъектовСлужебный.ДобавитьРасширениеПоляНомер(СхемаКомпоновкиДанных);
			КонецЕсли;
			ИсточникиПолей.Добавить(СхемаКомпоновкиДанных, ОбъектМетаданных.ПолноеИмя());
		Иначе
			ТекстЗапроса = ТекстЗапроса(ОбъектМетаданных.ПолноеИмя());
			СхемаКомпоновкиДанных= СхемаКомпоновкиДанных(ТекстЗапроса);
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПрефиксацияОбъектов") Тогда
				МодульПрефиксацияОбъектовСлужебный = ОбщегоНазначения.ОбщийМодуль("ПрефиксацияОбъектовСлужебный");
				МодульПрефиксацияОбъектовСлужебный.ДобавитьРасширениеПоляНомер(СхемаКомпоновкиДанных);
			КонецЕсли;
			ИсточникиПолей.Добавить(СхемаКомпоновкиДанных, ОбъектМетаданных.ПолноеИмя());
			
			Если ОбъектМетаданных.Макеты.Найти("ДополнительныеДанныеПечати") <> Неопределено Тогда
				МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя());
				СхемаКомпоновкиДанных = МенеджерОбъекта.ПолучитьМакет("ДополнительныеДанныеПечати");
				ИсточникиПолей.Добавить(СхемаКомпоновкиДанных, ОбъектМетаданных.ПолноеИмя());
			КонецЕсли;
		КонецЕсли;
		
		СхемаКомпоновкиДанных = СхемаКомпоновкиДанныхКонтактнойИнформации(ОбъектМетаданных.ПолноеИмя());
		Если СхемаКомпоновкиДанных <> Неопределено Тогда
			ИсточникиПолей.Добавить(СхемаКомпоновкиДанных, ОбъектМетаданных.ПолноеИмя() + ".КонтактнаяИнформация");
		КонецЕсли;
		
		СхемаКомпоновкиДанных = СхемаКомпоновкиДанныхДополнительныхРеквизитовИСведений(ОбъектМетаданных.ПолноеИмя());
		Если СхемаКомпоновкиДанных <> Неопределено Тогда
			ИсточникиПолей.Добавить(СхемаКомпоновкиДанных, ОбъектМетаданных.ПолноеИмя() + ".ДополнительныеРеквизитыИСведения");
		КонецЕсли;
		
	КонецЕсли;
	
	Если ДобавитьОбщиеРеквизиты Тогда
		ИсточникиПолей.Добавить(ПолучитьОбщийМакет("ДанныеПечатиОбщиеРеквизиты"), "ОбщиеРеквизиты");	
	КонецЕсли;

	Если СтрЗаканчиваетсяНа(ИмяИсточникаПолей, ".Наименование") Или СтрЗаканчиваетсяНа(ИмяИсточникаПолей, ".НаименованиеДляПечати") Тогда
		ИсточникиПолей.Добавить(ПолучитьОбщийМакет("ДанныеПечатиРегистрСимволов"), "ДанныеПечатиРегистрСимволов");	
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Валюты") Тогда
		Если ТипИсточникаПолей = Метаданные.ОпределяемыеТипы.ДенежнаяСуммаЛюбогоЗнака.Тип
			Или ТипИсточникаПолей = Метаданные.ОпределяемыеТипы.ДенежнаяСуммаНеотрицательная.Тип Тогда
				МодульРаботаСКурсамиВалют = ОбщегоНазначения.ОбщийМодуль("РаботаСКурсамиВалют");
				МодульРаботаСКурсамиВалют.ПодключитьИсточникДанныхПечатиЧислоПрописью(ИсточникиПолей);
		КонецЕсли;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность.Печать") Тогда
		МодульУправлениеПечатьюМультиязычность = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатьюМультиязычность");
		МодульУправлениеПечатьюМультиязычность.ПриОпределенииИсточниковДанныхПечати(ИмяИсточникаПолей, ИсточникиПолей);
	КонецЕсли;
	
	ИнтеграцияПодсистемБСП.ПриОпределенииИсточниковДанныхПечати(ИмяИсточникаПолей, ИсточникиПолей);
	УправлениеПечатьюПереопределяемый.ПриОпределенииИсточниковДанныхПечати(ИмяИсточникаПолей, ИсточникиПолей);
	
	Возврат ИсточникиПолей;
	
КонецФункции

Процедура ПриПодготовкеДанныхПечати(Объекты, ВнешниеНаборыДанных, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка, ДополнительныеПараметры)
	
	Если ИдентификаторСхемыКомпоновкиДанных = "ОбщиеРеквизиты" Тогда
		ВнешниеНаборыДанных.Вставить("Данные", ОбщиеРеквизитыПечатныхФорм(Объекты));
		Возврат;
	КонецЕсли;

	Если СтрЗаканчиваетсяНа(ИдентификаторСхемыКомпоновкиДанных, ".КонтактнаяИнформация") Тогда
		ВнешниеНаборыДанных.Вставить("Данные", КонтактнаяИнформация(
			Объекты, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка, ДополнительныеПараметры));
		Возврат;
	КонецЕсли;	
	
	Если СтрЗаканчиваетсяНа(ИдентификаторСхемыКомпоновкиДанных, ".ДополнительныеРеквизитыИСведения") Тогда
		ВнешниеНаборыДанных.Вставить("Данные", ДополнительныеРеквизитыИСведения(
			Объекты, ИдентификаторСхемыКомпоновкиДанных,  КодЯзыка));
		Возврат;
	КонецЕсли;	
	
	Если ИдентификаторСхемыКомпоновкиДанных = "ДанныеПечатиРегистрСимволов" Тогда
		ВнешниеНаборыДанных.Вставить("Данные", ДанныеПечатиРегистрСимволов(Объекты));
		Возврат;
	КонецЕсли;
	
		
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность.Печать") Тогда
		МодульУправлениеПечатьюМультиязычность = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатьюМультиязычность");
		МодульУправлениеПечатьюМультиязычность.ПриПодготовкеДанныхПечати(
			Объекты, ВнешниеНаборыДанных, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка, ДополнительныеПараметры);
	КонецЕсли;
	
	ИнтеграцияПодсистемБСП.ПриПодготовкеДанныхПечати(Объекты, ВнешниеНаборыДанных, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка, ДополнительныеПараметры);
	УправлениеПечатьюПереопределяемый.ПриПодготовкеДанныхПечати(Объекты, ВнешниеНаборыДанных, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка, ДополнительныеПараметры);
	
КонецПроцедуры

Функция ОбщиеРеквизитыПечатныхФорм(Объекты)

	ОбщиеРеквизиты = Новый Структура;
	ОбщиеРеквизиты.Вставить("ТекущаяДата", ТекущаяДатаСеанса());
	ОбщиеРеквизиты.Вставить("ТекущийПользователь", Пользователи.ТекущийПользователь());
	ОбщиеРеквизиты.Вставить("ЗаголовокСистемы", ИмяЭтойИнформационнойБазы());
	ОбщиеРеквизиты.Вставить("АдресБазыВИнтернете", ОбщегоНазначения.АдресПубликацииИнформационнойБазыВИнтернете());
	ОбщиеРеквизиты.Вставить("АдресБазыВЛокальнойСети", ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети());
	ОбщиеРеквизиты.Вставить("ОсновнаяОрганизация", "");
	ОбщиеРеквизиты.Вставить("ОбратныйАдрес", "");
	ОбщиеРеквизиты.Вставить("ШтампЭП", "");
	
	Результат = Новый ТаблицаЗначений();
	Результат.Колонки.Добавить("Ссылка");
	Для Каждого Реквизит Из ОбщиеРеквизиты Цикл
		Результат.Колонки.Добавить(Реквизит.Ключ);
	КонецЦикла;
	
	Для Каждого Объект Из Объекты Цикл
		РеквизитыОбъекта = Результат.Добавить();
		ЗаполнитьЗначенияСвойств(РеквизитыОбъекта, ОбщиеРеквизиты);
		РеквизитыОбъекта.Ссылка = Объект;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция СхемаКомпоновкиДанных(ТекстЗапроса)
	
	СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
	
	ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
	ИсточникДанных.Имя = "ИсточникДанных1";
	ИсточникДанных.ТипИсточникаДанных = "local";
	
	НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
	НаборДанных.ИсточникДанных = "ИсточникДанных1";
	НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
	НаборДанных.Запрос = ТекстЗапроса;
	НаборДанных.Имя = "НаборДанных1";
	
	Возврат СхемаКомпоновкиДанных;
	
КонецФункции

Функция ТекстЗапроса(ТипыИзменяемыхОбъектов, ОграничитьВыборку = Ложь)
	
	ОбъектыМетаданных = Новый Массив;
	Для Каждого ИмяОбъекта Из СтрРазделить(ТипыИзменяемыхОбъектов, ",", Ложь) Цикл
		ОбъектыМетаданных.Добавить(ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта));
	КонецЦикла;
	
	СтруктураОбъектов = ОбщиеРеквизитыОбъектов(ТипыИзменяемыхОбъектов);
	
	Результат = "";
	ПсевдонимТаблицы = "ПсевдонимЗаданнойТаблицы";
	Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
		
		Если Не ПустаяСтрока(Результат) Тогда
			Результат = Результат + Символы.ПС + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС + Символы.ПС;
		КонецЕсли;
		
		ТекстЗапроса = "";
		
		Для Каждого ИмяРеквизита Из СтруктураОбъектов.Реквизиты Цикл
			Если СтрНачинаетсяС(ИмяРеквизита, "Удалить") Тогда
				Продолжить;
			КонецЕсли;
			Если Не ПустаяСтрока(ТекстЗапроса) Тогда
				ТекстЗапроса = ТекстЗапроса + "," + Символы.ПС;
			КонецЕсли;
			ТекстЗапроса = ТекстЗапроса + ПсевдонимТаблицы + "." + ИмяРеквизита + " КАК " + ИмяРеквизита;
		КонецЦикла;
		
		Для Каждого ТабличнаяЧасть Из СтруктураОбъектов.ТабличныеЧасти Цикл
			ИмяТабличнойЧасти = ТабличнаяЧасть.Ключ;
			Если СтрНачинаетсяС(ИмяТабличнойЧасти, "Удалить") Тогда
				Продолжить;
			КонецЕсли;
			ТекстЗапроса = ТекстЗапроса + "," + Символы.ПС + ПсевдонимТаблицы + "." + ИмяТабличнойЧасти + ".(";
			
			СтрокаРеквизитов = "НомерСтроки";
			РеквизитыТабличнойЧасти = ТабличнаяЧасть.Значение;
			Для Каждого ИмяРеквизита Из РеквизитыТабличнойЧасти Цикл
				Если Не ПустаяСтрока(СтрокаРеквизитов) Тогда
					СтрокаРеквизитов = СтрокаРеквизитов + "," + Символы.ПС;
				КонецЕсли;
				СтрокаРеквизитов = СтрокаРеквизитов + ИмяРеквизита;
			КонецЦикла;
			ТекстЗапроса = ТекстЗапроса + СтрокаРеквизитов +"
			|)";
		КонецЦикла;
		
		ТекстЗапроса = "ВЫБРАТЬ " + ?(ОграничитьВыборку, "ПЕРВЫЕ 1001 ", "") //@query-part
			+ ТекстЗапроса + Символы.ПС + "
			|ИЗ
			|	"+ ОбъектМетаданных.ПолноеИмя() + " КАК " + ПсевдонимТаблицы;
		
		Результат = Результат + ТекстЗапроса;
	КонецЦикла;
		
		
	Возврат Результат;
	
КонецФункции

Функция ОбщиеРеквизитыОбъектов(ТипыОбъектов) Экспорт
	
	ОбъектыМетаданных = Новый Массив;
	Для Каждого ИмяОбъекта Из СтрРазделить(ТипыОбъектов, ",", Ложь) Цикл
		ОбъектыМетаданных.Добавить(ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта));
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("Реквизиты", Новый Массив);
	Результат.Вставить("ТабличныеЧасти", Новый Структура);
	
	Если ОбъектыМетаданных.Количество() = 0 Тогда
		Возврат Результат;
	КонецЕсли;
		
	ОбщийСписокРеквизитов = СписокЭлементов(ОбъектыМетаданных[0].Реквизиты, Ложь);
	Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
		ОбщийСписокРеквизитов = ПересечениеРеквизитов(ОбщийСписокРеквизитов, ОбъектыМетаданных[Индекс].Реквизиты);
	КонецЦикла;
	
	СтандартныеРеквизиты = ОбъектыМетаданных[0].СтандартныеРеквизиты;
	Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
		СтандартныеРеквизиты = ПересечениеРеквизитов(СтандартныеРеквизиты, ОбъектыМетаданных[Индекс].СтандартныеРеквизиты);
	КонецЦикла;
	Для Каждого Реквизит Из СтандартныеРеквизиты Цикл // ОписаниеСтандартногоРеквизита
		Если Реквизит.Имя = "ИмяПредопределенныхДанных"
			Или Реквизит.Имя = "Предопределенный"
			Или Реквизит.Имя = "ПометкаУдаления" Тогда
			Продолжить;
		КонецЕсли;
		ОбщийСписокРеквизитов.Добавить(Реквизит);
	КонецЦикла;
	
	Результат.Реквизиты = СписокЭлементов(ОбщийСписокРеквизитов);
	
	ТабличныеЧасти = СписокЭлементов(ОбъектыМетаданных[0].ТабличныеЧасти);
	Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
		ТабличныеЧасти = ПересечениеМножеств(ТабличныеЧасти, СписокЭлементов(ОбъектыМетаданных[Индекс].ТабличныеЧасти));
	КонецЦикла;
	
	Для Каждого ИмяТабличнойЧасти Из ТабличныеЧасти Цикл
		РеквизитыТабличнойЧасти = СписокЭлементов(ОбъектыМетаданных[0].ТабличныеЧасти[ИмяТабличнойЧасти].Реквизиты, Ложь);
		Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
			РеквизитыТабличнойЧасти = ПересечениеРеквизитов(РеквизитыТабличнойЧасти, ОбъектыМетаданных[Индекс].ТабличныеЧасти[ИмяТабличнойЧасти].Реквизиты);
		КонецЦикла;
		Если РеквизитыТабличнойЧасти.Количество() > 0 Тогда
			Результат.ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, СписокЭлементов(РеквизитыТабличнойЧасти));
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПересечениеМножеств(Множество1, Множество2) Экспорт
	
	Индекс = Новый Соответствие;
	Для Каждого Элемент Из Множество1 Цикл
		Индекс[Элемент] = Ложь;
	КонецЦикла;
	
	Для Каждого Элемент Из Множество2 Цикл
		Если Индекс[Элемент] <> Неопределено Тогда
			Индекс[Элемент] = Истина;
		КонецЕсли;
	КонецЦикла;

	Результат = Новый Массив;

	Для Каждого Элемент Из Множество1 Цикл
		Если Индекс[Элемент] = Истина Тогда
			Результат.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПересечениеРеквизитов(КоллекцияРеквизитов1, КоллекцияРеквизитов2)
	
	Результат = Новый Массив;
	
	Для Каждого Реквизит2 Из КоллекцияРеквизитов2 Цикл
		Для Каждого Реквизит1 Из КоллекцияРеквизитов1 Цикл
			Если Реквизит1.Имя = Реквизит2.Имя 
				И (Реквизит1.Тип = Реквизит2.Тип Или Реквизит1.Имя = "Ссылка") Тогда
				Результат.Добавить(Реквизит1);
				Прервать;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//   Коллекция - Массив из ОбъектМетаданныхРеквизит
//             - Массив из ОбъектМетаданныхТабличнаяЧасть
//   ТолькоИмена - Булево
// Возвращаемое значение:
//   Массив
//
Функция СписокЭлементов(Коллекция, ТолькоИмена = Истина)
	Результат = Новый Массив;
	Для Каждого Элемент Из Коллекция Цикл
		Если ТолькоИмена Тогда
			Результат.Добавить(Элемент.Имя);
		Иначе
			Результат.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;
	Возврат Результат;
КонецФункции

Функция ИмяЭтойИнформационнойБазы()
	
	УстановитьПривилегированныйРежим(Истина);
	Результат = Константы.ЗаголовокСистемы.Получить();
	Возврат ?(ПустаяСтрока(Результат), Метаданные.Синоним, Результат);
	
КонецФункции

Процедура ДобавитьКомандыПечати(КомандыПечати, ОбъектМетаданных)
	
	Владелец = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ОбъектМетаданных, Ложь);
	Если Владелец = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	МакетыПечатныхФорм.Идентификатор,
	|	МакетыПечатныхФорм.Представление КАК Представление,
	|	МакетыПечатныхФорм.УсловиеВидимости КАК УсловияВидимости
	|ИЗ
	|	Справочник.МакетыПечатныхФорм.ИсточникиДанных КАК МакетыПечатныхФормИсточникиДанных
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.МакетыПечатныхФорм КАК МакетыПечатныхФорм
	|		ПО МакетыПечатныхФормИсточникиДанных.Ссылка = МакетыПечатныхФорм.Ссылка
	|ГДЕ
	|	МакетыПечатныхФормИсточникиДанных.ИсточникДанных = &Владелец
	|	И МакетыПечатныхФорм.Используется
	|	И НЕ МакетыПечатныхФорм.ПометкаУдаления";
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Владелец", Владелец);
	Выборка = Запрос.Выполнить().Выбрать();

	Пока Выборка.Следующий() Цикл
		КомандаПечати = КомандыПечати.Добавить();
		ЗаполнитьЗначенияСвойств(КомандаПечати, Выборка);
		КомандаПечати.Идентификатор = "ПФ_" + Строка(КомандаПечати.Идентификатор);
		КомандаПечати.МенеджерПечати = ИмяМодуляПечати();
		
		УсловияВидимости = Выборка.УсловияВидимости.Получить();
		Если ЗначениеЗаполнено(УсловияВидимости) Тогда
			Для Каждого Условие Из УсловияВидимости Цикл
				ПодключаемыеКоманды.ДобавитьУсловиеВидимостиКоманды(КомандаПечати, Условие.Реквизит, Условие.Значение, Условие.ВидСравнения); 
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ФорматПоУмолчанию(ОписаниеТипов)
	
	Формат = "";
	Если ОписаниеТипов = Неопределено Или ОписаниеТипов.Типы().Количество() <> 1 Тогда
		Возврат Формат;
	КонецЕсли;
	
	Тип = ОписаниеТипов.Типы()[0];
	
	Если Тип = Тип("Число") Тогда
		Формат = СтрШаблон("ЧЦ=%1; ЧДЦ=%2",
			ОписаниеТипов.КвалификаторыЧисла.Разрядность,
			ОписаниеТипов.КвалификаторыЧисла.РазрядностьДробнойЧасти);
	ИначеЕсли Тип = Тип("Дата") Тогда
		Если ОписаниеТипов.КвалификаторыДаты.ЧастиДаты = ЧастиДаты.Дата Тогда
			Формат = "ДЛФ=D";
		Иначе
			Формат = "ДЛФ=DT";
		КонецЕсли;
	ИначеЕсли Тип = Тип("Булево") Тогда
		Формат = НСтр("ru = 'БЛ=Нет; БИ=Да'");
	КонецЕсли;
	
	Возврат Формат;
	
КонецФункции

Функция СхемаКомпоновкиДанныхИзТаблицыЗначений(ТаблицаЗначений)
	
	Возврат КонструкторФормулСлужебный.СхемаКомпоновкиДанныхИзТаблицыЗначений(ТаблицаЗначений);
	
КонецФункции

Функция СхемаКомпоновкиДанныхИзДереваЗначений(ДеревоЗначений)
	
	Возврат КонструкторФормулСлужебный.СхемаКомпоновкиДанныхИзДереваЗначений(ДеревоЗначений);
	
КонецФункции

Функция КартинкаИзФайла(Файл)
	
	Результат = Новый Картинка;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		МодульРаботаСФайламиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебный");
		МодульРаботаСФайлами = ОбщегоНазначения.ОбщийМодуль("РаботаСФайлами");

		ТипыПрисоединенныхФайлов = МодульРаботаСФайламиСлужебный.ТипыПрисоединенныхФайлов();
		Если ЗначениеЗаполнено(Файл) И ТипыПрисоединенныхФайлов.СодержитТип(ТипЗнч(Файл)) Тогда
			ДвоичныеДанные = МодульРаботаСФайлами.ДвоичныеДанныеФайла(Файл, Ложь);
			Если ДвоичныеДанные <> Неопределено Тогда
				Результат = Новый Картинка(ДвоичныеДанные, Истина);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  ТабличныйДокумент, ДвоичныеДанные - макет.
//
Функция ПредставлениеМакета(ПутьКМакету, КодЯзыка)
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Макет ""%1"" не существует. Операция прервана.'"), ПутьКМакету);
	ЧастиПути = СтрРазделить(ПутьКМакету, ".", Истина);
	
	НайденныйМакет = Справочники.МакетыПечатныхФорм.СсылкаМакета(ПутьКМакету);
	Если НайденныйМакет <> Неопределено Тогда
		Возврат Строка(НайденныйМакет);
	КонецЕсли;

	Если ЧастиПути.Количество() <> 2 И ЧастиПути.Количество() <> 3 Тогда
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	ИмяМакета = ЧастиПути[ЧастиПути.ВГраница()];
	ЧастиПути.Удалить(ЧастиПути.ВГраница());
	ИмяОбъекта = СтрСоединить(ЧастиПути, ".");
	
	ИменаПоиска = ИменаМакета(ИмяМакета, КодЯзыка);
	ЭтоОбщийМакет = СтрРазделить(ИмяОбъекта, ".").Количество() = 1;
	КоллекцияМакетов = Метаданные.ОбщиеМакеты;
	
	Если Не ЭтоОбщийМакет Тогда
		ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта);
		Если ОбъектМетаданных = Неопределено Тогда
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		КоллекцияМакетов = ОбъектМетаданных.Макеты;
	КонецЕсли;
	
	Для Каждого ИмяПоиска Из ИменаПоиска Цикл
		НайденныйМакет = КоллекцияМакетов.Найти(ИмяПоиска);
		Если НайденныйМакет <> Неопределено Тогда
			Возврат НайденныйМакет.Представление();
		КонецЕсли;
	КонецЦикла;
	
	ВызватьИсключение ТекстОшибки;
	
КонецФункции

Функция ДоступныеДляПереводаМакеты() Экспорт
	
	ДоступныеДляПереводаМакеты = Новый Соответствие;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность.Печать") Тогда
		МодульУправлениеПечатьюМультиязычность = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатьюМультиязычность");
		ДоступныеДляПереводаМакеты = МодульУправлениеПечатьюМультиязычность.ДоступныеДляПереводаМакеты();
	КонецЕсли;
	
	Возврат ДоступныеДляПереводаМакеты;
	
КонецФункции

Функция ДоступенПереводМакета(ПутьКМакету) Экспорт
	
	ОбъектМетаданныхМакета = ОбъектМетаданныхМакета(ПутьКМакету);
	Если ОбъектМетаданныхМакета = Неопределено Тогда
		Возврат Истина;
	КонецЕсли;
	
	Возврат ДоступныеДляПереводаМакеты()[ОбъектМетаданныхМакета] = Истина;
	
КонецФункции

Функция СхемаКомпоновкиДанныхКонтактнойИнформации(ИмяОбъектаМетаданных)
	
	ВидыКонтактнойИнформации = Неопределено;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");

		ВидыКонтактнойИнформации = МодульУправлениеКонтактнойИнформацией.ВидыКонтактнойИнформацииОбъекта(
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИмяОбъектаМетаданных).ПустаяСсылка());
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ВидыКонтактнойИнформации) Тогда
		Возврат Неопределено;
	КонецЕсли;
		
	СписокПолей = ТаблицаПолейДанныхПечати();
	
	Поле = СписокПолей.Добавить();
	Поле.Идентификатор = "Ссылка";
	Поле.Представление = НСтр("ru = 'Ссылка'");
	Поле.ТипЗначения = Новый ОписаниеТипов();	

	Для Каждого ВидКонтактнойИнформации Из ВидыКонтактнойИнформации Цикл
		Если Не ЗначениеЗаполнено(ВидКонтактнойИнформации.ИдентификаторДляФормул) Тогда
			Продолжить;
		КонецЕсли;

		Поле = СписокПолей.Добавить();
		Поле.Идентификатор = ВидКонтактнойИнформации.ИдентификаторДляФормул;
		Поле.Представление = ВидКонтактнойИнформации.Наименование;
		Поле.ТипЗначения = Новый ОписаниеТипов("Строка");
	КонецЦикла;
	
	Если СписокПолей.Количество() = 1 Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Возврат СхемаКомпоновкиДанныхПечати(СписокПолей);
	
КонецФункции

Функция СхемаКомпоновкиДанныхДополнительныхРеквизитовИСведений(ИмяОбъектаМетаданных)
	
	СписокПолей = ТаблицаПолейДанныхПечати();
	СписокПолей.Колонки.Добавить("Свойство");
	
	ВидыСвойств = Новый Массив;
	ВидыСвойств.Добавить("ДополнительныеРеквизиты");
	ВидыСвойств.Добавить("ДополнительныеСведения");
	
	МодульУправлениеСвойствамиСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствамиСлужебный");
	Если МодульУправлениеСвойствамиСлужебный <> Неопределено Тогда
		Для Каждого ВидСвойства Из ВидыСвойств Цикл
			СписокСвойств = МодульУправлениеСвойствамиСлужебный.СписокСвойствДляВидаОбъектов(ИмяОбъектаМетаданных, ВидСвойства);
			Если СписокСвойств <> Неопределено Тогда
				Для Каждого Элемент Из СписокСвойств Цикл
					Поле = СписокПолей.Добавить();
					Поле.Свойство = Элемент.Свойство;
					Поле.Представление = Элемент.Наименование;
					Поле.ТипЗначения = Элемент.ТипЗначения;
					Поле.Формат = Элемент.ФорматСвойства;
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Свойства = СписокПолей.ВыгрузитьКолонку("Свойство");
	
	Если Свойства.Количество() = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ИдентификаторыДляФормул = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(Свойства, "ИдентификаторДляФормул");
	
	Для Каждого СтрокаТаблицы Из СписокПолей Цикл
		СтрокаТаблицы.Идентификатор = ИдентификаторыДляФормул[СтрокаТаблицы.Свойство];
	КонецЦикла;
	
	Поле = СписокПолей.Добавить();
	Поле.Идентификатор = "Ссылка";
	Поле.Представление = НСтр("ru = 'Ссылка'");
	Поле.ТипЗначения = Новый ОписаниеТипов();	

	Возврат СхемаКомпоновкиДанныхПечати(СписокПолей);
	
КонецФункции

// Получает контактную информацию для списка однотипных объектов.
//
Функция КонтактнаяИнформация(ИсточникиДанных, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка, ДополнительныеПараметры)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
	Иначе
		Возврат Неопределено;
	КонецЕсли;
	
	Если Не СтрЗаканчиваетсяНа(ИдентификаторСхемыКомпоновкиДанных, "КонтактнаяИнформация") Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ЧастиСтроки = СтрРазделить(ИдентификаторСхемыКомпоновкиДанных, ".", Истина);
	ЧастиСтроки.Удалить(ЧастиСтроки.ВГраница());
	
	ИмяОбъектаМетаданных = СтрСоединить(ЧастиСтроки, ".");
	
	Данные = Новый ТаблицаЗначений();
	Данные.Колонки.Добавить("Ссылка");
	
	ВидыКонтактнойИнформацииОбъекта = МодульУправлениеКонтактнойИнформацией.ВидыКонтактнойИнформацииОбъекта(
		ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИмяОбъектаМетаданных).ПустаяСсылка());
		
	ИдентификаторыДляФормул = Новый Соответствие();
	Для Каждого ВидКонтактнойИнформации Из ВидыКонтактнойИнформацииОбъекта Цикл
		Идентификатор = ВидКонтактнойИнформации.ИдентификаторДляФормул;
		Если Не ЗначениеЗаполнено(Идентификатор) Тогда
			Продолжить;
		КонецЕсли;
		ИдентификаторыДляФормул.Вставить(ВидКонтактнойИнформации.Ссылка, Идентификатор);
		Данные.Колонки.Добавить(Идентификатор);
	КонецЦикла;
	
	Владельцы = Новый Массив;
	Для Каждого ОписаниеИсточникаДанных Из ДополнительныеПараметры.ОписанияИсточниковДанных Цикл
		Владелец = ОписаниеИсточникаДанных.Владелец;
		Если ЗначениеЗаполнено(Владелец) И ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Владелец))
			И ОбщегоНазначения.ЭтоДокумент(Владелец.Метаданные()) Тогда
			Владельцы.Добавить(Владелец);
		КонецЕсли;
	КонецЦикла;
	
	Если ЗначениеЗаполнено(Владельцы) Тогда
		ДополнительныеПараметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных = Истина;
		ИсточникиДанных = Владельцы;
	КонецЕсли;
	
	ДатыСведений = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(Владельцы, "Дата");
	
	Для Каждого ОписаниеИсточникаДанных Из ДополнительныеПараметры.ОписанияИсточниковДанных Цикл
		Объект = ОписаниеИсточникаДанных.Значение;
		
		СтрокаТаблицы = Данные.Добавить();
		СтрокаТаблицы.Ссылка = Объект;
		Если ДополнительныеПараметры.ДанныеИсточниковСгруппированыПоВладельцуИсточникаДанных Тогда
			СтрокаТаблицы.Ссылка = ОписаниеИсточникаДанных.Владелец;
		КонецЕсли;
		
		ДатаСведений = ДатыСведений[ОписаниеИсточникаДанных.Владелец];
		Если Не ЗначениеЗаполнено(ДатаСведений) Тогда
			ДатаСведений = ТекущаяДатаСеанса();
		КонецЕсли;
		
		Отбор = МодульУправлениеКонтактнойИнформацией.ОтборКонтактнойИнформации();
		Отбор.КодЯзыка = КодЯзыка;
		Отбор.Дата = ДатаСведений;

		КонтактнаяИнформацияОбъектов = МодульУправлениеКонтактнойИнформацией.КонтактнаяИнформация(
			ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Объект), Отбор);
		
		Для Каждого КонтактнаяИнформацияОбъекта Из КонтактнаяИнформацияОбъектов Цикл
			Идентификатор = ИдентификаторыДляФормул[КонтактнаяИнформацияОбъекта.Вид];
			Если Не ЗначениеЗаполнено(Идентификатор) Тогда
				Продолжить;
			КонецЕсли;
	
			СтрокаТаблицы[Идентификатор] = КонтактнаяИнформацияОбъекта.Представление;
		КонецЦикла;

	КонецЦикла;
	
	Возврат Данные;
	
КонецФункции

// Получает дополнительные реквизиты и сведения для списка однотипных объектов.
//
Функция ДополнительныеРеквизитыИСведения(Объекты, ИдентификаторСхемыКомпоновкиДанных, КодЯзыка)
	
	Данные = Новый ТаблицаЗначений();
	Данные.Колонки.Добавить("Ссылка");
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
		Возврат Данные;
	КонецЕсли;
	
	Если Не СтрЗаканчиваетсяНа(ИдентификаторСхемыКомпоновкиДанных, "ДополнительныеРеквизитыИСведения") Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ЧастиСтроки = СтрРазделить(ИдентификаторСхемыКомпоновкиДанных, ".", Истина);
	ЧастиСтроки.Удалить(ЧастиСтроки.ВГраница());
	
	ИмяОбъектаМетаданных = СтрСоединить(ЧастиСтроки, ".");
	
	ВидыСвойств = Новый Массив;
	ВидыСвойств.Добавить("ДополнительныеРеквизиты");
	ВидыСвойств.Добавить("ДополнительныеСведения");
	
	СписокСвойств = Новый Массив;
	
	МодульУправлениеСвойствамиСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствамиСлужебный");
	Для Каждого ВидСвойства Из ВидыСвойств Цикл
		Свойства = МодульУправлениеСвойствамиСлужебный.СписокСвойствДляВидаОбъектов(ИмяОбъектаМетаданных, ВидСвойства).ВыгрузитьКолонку("Свойство");
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(СписокСвойств, Свойства);
	КонецЦикла;
	
	ИдентификаторыДляФормул = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(СписокСвойств, "ИдентификаторДляФормул");
	
	Для Каждого Свойство Из СписокСвойств Цикл
		Идентификатор = ИдентификаторыДляФормул[Свойство];
		Если Не ЗначениеЗаполнено(Идентификатор) Тогда
			Продолжить;
		КонецЕсли;
		
		Данные.Колонки.Добавить(Идентификатор);
	КонецЦикла;
	
	Для Каждого Объект Из Объекты Цикл
		СтрокаТаблицы = Данные.Добавить();
		СтрокаТаблицы.Ссылка = Объект;
	КонецЦикла;
	
	МодульУправлениеСвойствами = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствами");
	ЗначенияСвойствОбъектов = МодульУправлениеСвойствами.ЗначенияСвойств(Объекты, , , , КодЯзыка);
	
	Для Каждого ЗначенияСвойствОбъекта Из ЗначенияСвойствОбъектов Цикл
		Свойство = ЗначенияСвойствОбъекта.Свойство;
		Объект = ЗначенияСвойствОбъекта.ВладелецСвойств;

		НайденныеСтроки = Данные.НайтиСтроки(Новый Структура("Ссылка", Объект));
		Для Каждого СтрокаТаблицы Из НайденныеСтроки Цикл
			СтрокаТаблицы[ИдентификаторыДляФормул[Свойство]] = ЗначенияСвойствОбъекта.Значение;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Данные;

КонецФункции

Функция СтрокаЛатиницей(Строка) Экспорт
	
	Возврат СтроковыеФункции.СтрокаЛатиницей(Строка);
		
КонецФункции

Функция ДанныеПечатиРегистрСимволов(Объекты)
	
	ДанныеПечати = Новый ТаблицаЗначений();
	ДанныеПечати.Колонки.Добавить("Ссылка");
	ДанныеПечати.Колонки.Добавить("ВсеПрописные");
	ДанныеПечати.Колонки.Добавить("ВсеСтрочные");
	
	Для Каждого Объект Из Объекты Цикл
		НоваяСтрока = ДанныеПечати.Добавить();
		НоваяСтрока.Ссылка = Объект;
		НоваяСтрока.ВсеПрописные = ВРег(Объект);
		НоваяСтрока.ВсеСтрочные = НРег(Объект);
	КонецЦикла;
	
	Возврат ДанныеПечати;
	
КонецФункции

Процедура ПодготовитьУзлыУсловныхОбластей(ДеревоXML, Гиперссылки)
	ТаблицаСортировки = Новый ТаблицаЗначений();
	ТаблицаСортировки.Колонки.Добавить("Ключ");
	ТаблицаСортировки.Колонки.Добавить("Значение");
	ТаблицаСортировки.Колонки.Добавить("Длина");
	
	ПолныйТекст = ДеревоXML.Строки[0].ПолныйТекст;
	ИмяТега = ИмяТегаУсловие();
	
	
	ФрагментыТекста = СтрРазделить(ПолныйТекст, "{", Ложь);
	Для Каждого ФрагментТекста Из ФрагментыТекста Цикл
		ПозицияИмениТега = СтрНайти(ФрагментТекста, ИмяТега);
		Если ПозицияИмениТега И ПозицияИмениТега < 3 Тогда
			ФрагментыСтрок = СтрРазделить(ФрагментТекста, "}", Ложь);
									
			НоваяСтрока = ТаблицаСортировки.Добавить();
			НоваяСтрока.Ключ 		= "{"+ФрагментыСтрок[0]+"}";
			НоваяСтрока.Длина 		= НоваяСтрока.Ключ;
			НоваяСтрока.Значение 	= НоваяСтрока.Ключ;
		КонецЕсли;
	КонецЦикла;
	
	ТаблицаСортировки.Сортировать("Длина Убыв");
	ВсеУзлыУсловий = Новый Массив;
	
	УзлыУсловия = Новый Массив;
	Для Каждого СоответствиеЗамены Из ТаблицаСортировки Цикл
		УзлыУсловия.Очистить(); 
		УправлениеПечатьюСлужебный.НайтиУзлы(ДеревоXML, СоответствиеЗамены.Ключ, УзлыУсловия);

		Для Каждого Узел Из УзлыУсловия Цикл
			Если Узел.Строки.Количество() Тогда
				СобратьСтроки(Узел);
				УправлениеПечатьюСлужебный.ВосстановитьПолныйТекст(Узел, Гиперссылки);
			КонецЕсли;
		КонецЦикла;
		ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ВсеУзлыУсловий, УзлыУсловия, Истина);
	КонецЦикла;
	
	ФрагментыУзла = Новый Массив;
	Для Каждого УзелУсловия Из ВсеУзлыУсловий Цикл
		ФрагментыУзла.Очистить();
		ФрагментыТекста = СтрРазделить(УзелУсловия.Текст, "{", Ложь);
		Для Каждого ФрагментТекста Из ФрагментыТекста Цикл
			ПозицияИмениТега = СтрНайти(ФрагментТекста, ИмяТега);
			Если ПозицияИмениТега И ПозицияИмениТега < 3 Тогда
				ФрагментыСтрок = СтрРазделить(ФрагментТекста, "}", Ложь);
				
				ФрагментыУзла.Добавить("{"+ФрагментыСтрок[0]+"}");
				Для ИндексФрагмента = 1 По ФрагментыСтрок.ВГраница() Цикл
					ФрагментыУзла.Добавить(ФрагментыСтрок[ИндексФрагмента]);
				КонецЦикла;
			Иначе
				ФрагментыУзла.Добавить(ФрагментТекста);
			КонецЕсли;
		КонецЦикла;
		РазделитьПрогон(УзелУсловия, ФрагментыУзла, Гиперссылки);
	КонецЦикла;
КонецПроцедуры

Процедура РазделитьПрогон(УзелУсловия, ФрагментыУзла, Гиперссылки)
	РодительДобавления = УзелУсловия.Родитель;
	ИндексДобавления = РодительДобавления.Строки.Индекс(УзелУсловия);
	Для ИндексФрагментаУзла = 0 По ФрагментыУзла.ВГраница() Цикл
		
		Если ИндексФрагментаУзла = 0 Тогда
			УзелДляОбработки = УзелУсловия;
		Иначе
			УзелДляОбработки = УправлениеПечатьюСлужебный.СкопироватьУзел(РодительДобавления, ИндексДобавления, УзелУсловия);
		КонецЕсли;
		ИндексДобавления = ИндексДобавления + 1;
		
		УзелДляОбработки.Текст = ФрагментыУзла[ИндексФрагментаУзла];
	КонецЦикла;
	УправлениеПечатьюСлужебный.ВосстановитьПолныйТекст(РодительДобавления, Гиперссылки);
КонецПроцедуры

Функция СобратьСтроки(Узел, УзелСборки = Неопределено, УзлыСборки = Неопределено,  Открытых = 0)
	
	Если Узел.ИмяТега =	"w:t" Тогда
	
		МассивФрагментов = СтрРазделить(Узел.Текст, "[{", Истина);
		ТекстУзла = Узел.Текст;		
		Отрывающихся = МассивФрагментов.ВГраница();
		Закрывающихся = 0; 
			
		Для Каждого ФрагментНачала Из МассивФрагментов Цикл
			ФрагментНачала = СтрРазделить(ФрагментНачала, "}]", истина);
			Закрывающихся = Закрывающихся + ФрагментНачала.ВГраница();
		КонецЦикла;
		
		Если УзелСборки = Неопределено Тогда
			Если Отрывающихся > 0 Тогда
				УзелСборки = Узел;
				УзелСборки.Текст ="";
				Если УзлыСборки = Неопределено Тогда
					УзлыСборки = Новый Массив();
				КонецЕсли;
				УзлыСборки.Добавить(Узел);
			КонецЕсли;
		Иначе
			Узел.Текст = "";
		КонецЕсли;
						
		Если УзелСборки = Неопределено Тогда
			Узел.Текст = ТекстУзла;
		Иначе						
			УзелСборки.Текст = УзелСборки.Текст + ТекстУзла;
		КонецЕсли; 
				
		Если УзелСборки <> Неопределено И Открытых + Отрывающихся - Закрывающихся = 0 Тогда
			УзелСборки = Неопределено;
		КонецЕсли;
		
		Открытых = Открытых + Отрывающихся - Закрывающихся;
	Иначе
		Для Каждого СтрокаУзла Из Узел.Строки Цикл
			СобратьСтроки(СтрокаУзла, УзелСборки, УзлыСборки, Открытых);			
		КонецЦикла;
	КонецЕсли;
	Возврат УзлыСборки;
КонецФункции

Функция КопияДереваМакета(ДеревоМакета)
	ДеревоМакетаДляЗаполнения = ОбщегоНазначения.СкопироватьРекурсивно(ДеревоМакета);
	КаталогПриемник = ФайловаяСистема.СоздатьВременныйКаталог();
	СтруктураДокумента = ДеревоМакетаДляЗаполнения.СтруктураДокумента;
	КаталогКартинок = СтруктураДокумента.КаталогКартинок;
	КаталогКартинок = СтрЗаменить(КаталогКартинок, ДеревоМакетаДляЗаполнения.ИмяКаталога, КаталогПриемник);
	КаталогИсточник = ДеревоМакетаДляЗаполнения.ИмяКаталога;
	ДеревоМакетаДляЗаполнения.ИмяКаталога = КаталогПриемник;
	СтруктураДокумента.КаталогКартинок = КаталогКартинок;
	УправлениеПечатьюСлужебный.КопироватьСодержимоеКаталога(КаталогИсточник, КаталогПриемник);
	ДеревоМакетаДляЗаполнения.Вставить("ОбластиДляВывода", Новый Массив);
	Возврат ДеревоМакетаДляЗаполнения;
КонецФункции

Функция ПолучитьЗначениеПараметровОбъекта(ДанныеПечати, ОбъектПечати, ДеревоМакета, КодЯзыка, ПараметрыПечати, ПараметрыТекста)
	
	ДанныеОбъекта = ДанныеПечати[ОбъектПечати];
	НастройкиФорматаПолей = ДанныеПечати["НастройкиФорматаПолей"];
	
	СоответствиеСтроки = Новый Соответствие();
	Для Каждого ПараметрОбласти Из ПараметрыТекста Цикл
		Представление = УстановитьПредставлениеКартинку(КодЯзыка, ПараметрОбласти, НастройкиФорматаПолей, ДанныеОбъекта, ПараметрыПечати);
		СоответствиеСтроки.Вставить(ПараметрОбласти, Представление);
	КонецЦикла;
	Возврат СоответствиеСтроки;
		
КонецФункции

Функция ПолучитьДанныеОбласти(ДанныеПечати, ОбъектПечати, Область, ДеревоМакета, КодЯзыка, ПараметрыПечати)
	
	НастройкиФорматаПолей = ДанныеПечати["НастройкиФорматаПолей"];
	Результат = Новый Массив();
	
	МассивПараметровОбласти = Область.Параметры;
	
	Ссылка = ОбъектПечати;
	ИмяТаблицы = Область.Коллекция;
	
	СоответствиеСтрок = ДанныеПечати[Ссылка][ИмяТаблицы];	
	Для НомерСтрокиТабличнойЧасти = 1 По СоответствиеСтрок.Количество() Цикл
		ИсточникДанных = Новый Соответствие;
		ОбщегоНазначенияКлиентСервер.ДополнитьСоответствие(ИсточникДанных, ДанныеПечати[Ссылка]);
		Если ЗначениеЗаполнено(ИмяТаблицы) Тогда
			ДанныеСтрокиТабличнойЧасти = ДанныеПечати[Ссылка][ИмяТаблицы][НомерСтрокиТабличнойЧасти];
			Для Каждого КлючИЗначение Из ДанныеСтрокиТабличнойЧасти Цикл
				ИсточникДанных[ИмяТаблицы + "." + КлючИЗначение.Ключ] = КлючИЗначение.Значение;
			КонецЦикла;
		КонецЕсли;
		
		СоответствиеСтроки = Новый Соответствие();
		Для Каждого ПараметрОбласти Из МассивПараметровОбласти Цикл
			
			Представление = УстановитьПредставлениеКартинку(КодЯзыка, ПараметрОбласти, НастройкиФорматаПолей, ИсточникДанных, ПараметрыПечати);
			СоответствиеСтроки.Вставить(ПараметрОбласти, Представление);
			
		КонецЦикла;
		
		Результат.Добавить(СоответствиеСтроки);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция УстановитьПредставлениеКартинку(КодЯзыка, ПараметрОбласти, НастройкиФорматаПолей, Источник, ПараметрыПечати)
	
	ПараметрыТекста = НайтиПараметрыВТексте(Строка(ПараметрОбласти));
	ЗначенияПараметров = ЗначенияПараметров(ПараметрыТекста, Источник, НастройкиФорматаПолей, КодЯзыка);
	Представление = ПараметрОбласти;
	ЗначениеПервогоПараметра = ЗначенияПараметров[ПараметрыТекста[0]];
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		МодульРаботаСФайламиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебный");
		ТипПрисоединенныйФайл = МодульРаботаСФайламиСлужебный.ТипыПрисоединенныхФайлов();
	Иначе
		ТипПрисоединенныйФайл = Новый ОписаниеТипов();
	КонецЕсли;
	
	Если ЗначениеПервогоПараметра <> Неопределено И ТипПрисоединенныйФайл.СодержитТип(ТипЗнч(ЗначениеПервогоПараметра)) Тогда 
		Если ЗначениеЗаполнено(ЗначениеПервогоПараметра) Тогда
			Представление = Новый Структура("Ширина,Высота,АдресКартинки");
			
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
				МодульРаботаСФайламиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебный");
				МодульРаботаСФайлами = ОбщегоНазначения.ОбщийМодуль("РаботаСФайлами");

				ТипыПрисоединенныхФайлов = МодульРаботаСФайламиСлужебный.ТипыПрисоединенныхФайлов();
				Если ЗначениеЗаполнено(ЗначениеПервогоПараметра) И ТипыПрисоединенныхФайлов.СодержитТип(ТипЗнч(ЗначениеПервогоПараметра)) Тогда
					ДвоичныеДанные = МодульРаботаСФайлами.ДвоичныеДанныеФайла(ЗначениеПервогоПараметра, Ложь);
					Представление.АдресКартинки = ПоместитьВоВременноеХранилище(ДвоичныеДанные, Новый УникальныйИдентификатор());
				КонецЕсли;
			КонецЕсли;
			
			ВыводитьПодписьИПечать = Неопределено;
			ПараметрыПечати.Свойство("ПодписьИПечать", ВыводитьПодписьИПечать);
			
			Если СтрНайти(ПараметрыТекста[0], "Подпись") Тогда
				Если ВыводитьПодписьИПечать = Ложь Тогда
					Представление.АдресКартинки = "";
				КонецЕсли;
				Представление.Ширина = 30;
				Представление.Высота = 10;
			ИначеЕсли СтрНайти(ПараметрыТекста[0], "Печать") Тогда
				Если ВыводитьПодписьИПечать = Ложь Тогда
					Представление.АдресКартинки = "";
				КонецЕсли;
				Представление.Ширина = 40;
				Представление.Высота = 40;
			КонецЕсли;
		Иначе
			Представление = "";
		КонецЕсли;
	ИначеЕсли ТипЗнч(ЗначениеПервогоПараметра) = Тип("Картинка") Тогда
		Если ЗначениеЗаполнено(ЗначениеПервогоПараметра) Тогда
			Представление = Новый Структура("Ширина,Высота,АдресКартинки");
			ДвоичныеДанные = ЗначениеПервогоПараметра.ПолучитьДвоичныеДанные();
			Представление.АдресКартинки = ПоместитьВоВременноеХранилище(ДвоичныеДанные, Новый УникальныйИдентификатор());
		КонецЕсли;
	Иначе
		Представление = ЗаменитьВСтроке(ПараметрОбласти, ЗначенияПараметров);
	КонецЕсли;
	
	Возврат Представление;
	
КонецФункции

Процедура ДобавитьОператорВГруппу(Группа, Идентификатор, Знач Представление = Неопределено, Тип = Неопределено, ЭтоФункция = Ложь)
	
	Если Представление = Неопределено Тогда
		Представление = Идентификатор;
	КонецЕсли;
	
	Оператор = Группа.Строки.Добавить();
	Оператор.Идентификатор = Идентификатор;
	Если СтрРазделить(Представление, " ").Количество() > 1 Тогда
		Оператор.Представление = СтрЗаменить(ТРег(Представление), " ", "");
	Иначе
		Оператор.Представление = Представление;
	КонецЕсли;
	Оператор.ТипЗначения = Тип;
	Оператор.Картинка = БиблиотекаКартинок.Пустая;
	Оператор.ЭтоФункция = ЭтоФункция;

КонецПроцедуры

// Установить параметры в дереве.
// 
// Параметры:
//  СоответствиеЗамен - Соответствие из КлючИЗначение - содержит правила перестановки.
//  ДеревоXML - см. УправлениеПечатьюСлужебный.ПрочитатьXMLВДерево
//  ДеревоМакета - см. ИнициализироватьМакетОфисногоДокументаСКД
//  ДобавлятьСвязи - Булево - добавлять связи
//
Процедура УстановитьПараметрыВДереве(Знач СоответствиеЗамен, ДеревоXML, ДеревоМакета = Неопределено, ДобавлятьСвязи = Истина)
	
	ТаблицаСортировки = Новый ТаблицаЗначений();
	ТаблицаСортировки.Колонки.Добавить("Ключ");
	ТаблицаСортировки.Колонки.Добавить("Значение");
	ТаблицаСортировки.Колонки.Добавить("Длина");
	Для Каждого СоответствиеЗамены Из СоответствиеЗамен Цикл
		НоваяСтрока = ТаблицаСортировки.Добавить();
		НоваяСтрока.Ключ 		= СоответствиеЗамены.Ключ;
		НоваяСтрока.Длина 		= СтрДлина(СоответствиеЗамены.Ключ);
		НоваяСтрока.Значение 	= СоответствиеЗамены.Значение;
	КонецЦикла;
	
	ТаблицаСортировки.Сортировать("Длина Убыв");
	
	Для Каждого СоответствиеЗамены Из ТаблицаСортировки Цикл
		МассивУзлов = Новый Массив; 
		УправлениеПечатьюСлужебный.НайтиУзлы(ДеревоXML, СоответствиеЗамены.Ключ, МассивУзлов);
		
		Для Каждого Узел Из МассивУзлов Цикл
			Если Узел.Строки.Количество() = 0 ИЛИ Узел.ИмяТега = "w:hyperlink" Тогда
				УправлениеПечатьюСлужебный.УстановитьЗначениеВДокумент(Узел, СоответствиеЗамены, ДеревоМакета, ДобавлятьСвязи);
			Иначе
				МассивСобранныхУзлов = СобратьСтроки(Узел);
				Если МассивСобранныхУзлов = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				Для Каждого СобранныйУзел Из МассивСобранныхУзлов Цикл
					УправлениеПечатьюСлужебный.УстановитьЗначениеВДокумент(СобранныйУзел, СоответствиеЗамены, ДеревоМакета, ДобавлятьСвязи);
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
		
	КонецЦикла;

КонецПроцедуры

// Параметры:
//  КоллекцияПолей - см. КонструкторФормул.КоллекцияПолей
//
Функция ПоляКоллекции(КоллекцияПолей)
	
	Результат = Новый Массив;
	
	Для Каждого ОписаниеПоля Из КоллекцияПолей.Элементы Цикл
		Результат.Добавить(ОписаниеПоля.Поле);
		Если ОписаниеПоля.Папка Или ОписаниеПоля.Таблица Тогда
			ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Результат, ПоляКоллекции(ОписаниеПоля)); 
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция КоллекцияПолейОбщиеРеквизиты()
	
	Возврат КонструкторФормул.КоллекцияПолей(ПолучитьОбщийМакет("ДанныеПечатиОбщиеРеквизиты"));

КонецФункции

Функция ПолучитьПропущенногоРодителя(СтрокаДобавления, ДеревоДляВывода)
	Родители = Новый Массив;
	НайтиПропущенныхРодителей(Родители, ДеревоДляВывода, СтрокаДобавления);
	РодительДобавления = ДеревоДляВывода.Строки.Найти(Родители[0].Родитель.Индекс, "Индекс", Истина);  
	ИндексДобавления = Родители[0].Родитель.Строки.Индекс(Родители[0]); 
	
	Для Каждого Родитель Из Родители Цикл
		РодительДобавления = УправлениеПечатьюСлужебный.СкопироватьУзел(РодительДобавления, ИндексДобавления, Родитель);
		ИндексДобавления = 0;
	КонецЦикла;
	
	Возврат РодительДобавления;
КонецФункции

Процедура НайтиПропущенныхРодителей(Родители, ДеревоДляВывода, СтрокаДобавления)
	Если ДеревоДляВывода.Строки.Найти(СтрокаДобавления.Родитель.Индекс, "Индекс", Истина) = Неопределено Тогда
		Родители.Вставить(0, СтрокаДобавления.Родитель);
		НайтиПропущенныхРодителей(Родители, ДеревоДляВывода, СтрокаДобавления.Родитель);
	КонецЕсли;
КонецПроцедуры

Функция ПоместитьВХранилища(СтруктураПараметров, СодержимоеХранилищ, УникальныйИдентификаторХранилища)
	Если СодержимоеХранилищ.Количество() = 0 Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ТипПараметров = ТипЗнч(СтруктураПараметров);
	Если ТипПараметров = Тип("Строка") И ЭтоАдресВременногоХранилища(СтруктураПараметров) Тогда
		СтруктураПараметров = ПоместитьВоВременноеХранилище(СодержимоеХранилищ[СтруктураПараметров], УникальныйИдентификаторХранилища);
		Возврат Истина;
	ИначеЕсли ТипПараметров = Тип("Массив") Тогда
		Для Индекс = 0 По СтруктураПараметров.ВГраница() Цикл
			Элемент = СтруктураПараметров[Индекс];
			ПоместитьВХранилища(Элемент, СодержимоеХранилищ, УникальныйИдентификаторХранилища);
			СтруктураПараметров[Индекс] = Элемент;
		КонецЦикла;
	ИначеЕсли ТипПараметров = Тип("ТаблицаЗначений") Или ТипПараметров = Тип("СтрокаТаблицыЗначений") 
		Или ТипПараметров = Тип("СтрокаДереваЗначений") Тогда
		
		Для Каждого Элемент Из СтруктураПараметров Цикл
			ПоместитьВХранилища(Элемент, СодержимоеХранилищ, УникальныйИдентификаторХранилища);
		КонецЦикла;
	ИначеЕсли ТипПараметров = Тип("Структура") Или ТипПараметров = Тип("Соответствие") Тогда
		
		НовыеАдресаХранилищ = Новый Соответствие;
		Для Каждого Элемент Из СтруктураПараметров Цикл
			ЗначениеКоллекции = Элемент.Значение;
			Если ПоместитьВХранилища(ЗначениеКоллекции, СодержимоеХранилищ, УникальныйИдентификаторХранилища) Тогда
				НовыеАдресаХранилищ.Вставить(Элемент.Ключ, ЗначениеКоллекции);
			КонецЕсли;
		КонецЦикла;
		
		Для Каждого НовыйАдрес Из НовыеАдресаХранилищ Цикл
			СтруктураПараметров.Вставить(НовыйАдрес.Ключ, НовыйАдрес.Значение);
		КонецЦикла;
				
	ИначеЕсли  ТипПараметров = Тип("ДеревоЗначений") Тогда
		Для Каждого Элемент Из СтруктураПараметров.Строки Цикл
			ПоместитьВХранилища(Элемент, СодержимоеХранилищ, УникальныйИдентификаторХранилища);
		КонецЦикла;
	КонецЕсли;
	Возврат Ложь;
КонецФункции

Процедура ДобавитьГруппуОператоровФункцииДляТабличныхЧастей(СписокОператоров)
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ФункцииДляТабличныхЧастей";
	Группа.Представление = НСтр("ru = 'Функции для табличных частей'");
	Группа.Порядок = 5;
	Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	
	Тип = Новый ОписаниеТипов("Число");
	
	Префикс = ИмяМодуляПечати() + РазделительКоманды();
	
	ДобавитьОператорВГруппу(Группа, Префикс + "СуммаПоКолонке", НСтр("ru = 'Сумма по колонке'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, Префикс + "КоличествоСтрок", НСтр("ru = 'Количество строк'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, Префикс + "МаксимумПоКолонке", НСтр("ru = 'Максимум по колонке'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, Префикс + "МинимумПоКолонке", НСтр("ru = 'Минимум по колонке'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, Префикс + "СреднееПоКолонке", НСтр("ru = 'Среднее по колонке'"), Тип, Истина);
	
КонецПроцедуры

Процедура ЗапомнитьПоследнийИспользованныйМакет(ПутьКМакету)
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	ОбщегоНазначения.ХранилищеОбщихНастроекСохранить("Печать", "ПоследнийИспользованныйМакет", ПутьКМакету);
	
КонецПроцедуры

Функция ПоследнийИспользованныйМакет()
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	Возврат ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить("Печать", "ПоследнийИспользованныйМакет", Неопределено);
	
КонецФункции

Процедура ОчиститьПоследнийИспользованныйМакет()
	
	УстановитьОтключениеБезопасногоРежима(Истина);
	УстановитьПривилегированныйРежим(Истина);
	
	ОбщегоНазначения.ХранилищеОбщихНастроекУдалить("Печать", "ПоследнийИспользованныйМакет", Неопределено);
	
КонецПроцедуры

#КонецОбласти
